本文介绍了优先队列在解决特定算法问题中的应用,包括如何使用优先队列进行元素的高效管理和检索,特别是在需要维护一定顺序或查找特定元素的场景下。通过具体的代码示例,展示了如何实现基于优先级的元素插入和删除操作,以及如何利用优先队列解决最大战斗力团队的选取问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 

priority_queue是一个优先队列,队列里面按一定的规则排序,每次压入一个元素,都会排序

priority_queue<int,vector<int>,greater<int>> que2;//升序
priority_queue<int,vector<int>,less<int>> que3;//降序
///仅仅一个元素的优先队列

有多个元素的优先队列

struct node//第一种
{
    int x,y;
    bool friend operator < (node a,node b)
    {
        return a.x<b.x;
    }
}ee[1000];
//自定义排序规则

hdu4006

http://acm.hdu.edu.cn/showproblem.php?pid=4006

I表示加入一个数

Q询问第k大的数值

这道题用优先队列做,队列升序

用队首保存第k大的数,第k大数也是k个有序数了最小的数

每次压入后,如果队列元素大于k,就弹出最小的呢个数

ac:

#include<cstdio>
#include<iostream>
#include<queue>
#include<algorithm>
using namespace std;

int main()
{
    char ctr[2];
    int n,m,d;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        priority_queue<int,vector<int>,greater<int>> que;
        for(int i=0;i<n;i++)
        {
            scanf("%s",&ctr);
            if(ctr[0]=='I')
            {
                scanf("%d",&d);
                que.push(d);
                if(que.size()>m)
                    que.pop();
            }
            else{
                printf("%d\n",que.top());
            }
        }
    }
    return 0;
}

tokitsukaze and Soldier

题意:

在一个游戏中,tokitsukaze需要在n个士兵中选出一些士兵组成一个团去打副本。
第i个士兵的战力为v[i],团的战力是团内所有士兵的战力之和。
但是这些士兵有特殊的要求:如果选了第i个士兵,这个士兵希望团的人数不超过s[i]。(如果不选第i个士兵,就没有这个限制。)
tokitsukaze想知道,团的战力最大为多少

解析:

选择一个人后,从人数大于等于他的人里找s[i]个最大的人

#include<bits/stdc++.h>
#define ll long long
#define MAXN 100005
using namespace std;
struct node
{
    int v,s;
    friend bool operator <(node a,node b)
    {
        return a.s>b.s;
    }
}ee[MAXN];
struct NN
{
    int v;
    friend bool operator <(NN a,NN b)
    {
        return a.v>b.v;
    }
};
 
int main()
{
    int n,j=1;
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
        scanf("%d%d",&ee[i].v,&ee[i].s);
    sort(ee+1,ee+n+1);
    ll sum=0;
    ll ans=0;
    priority_queue<NN> que;
    for(int i=1;i<=n;i++)//按s[i]从大到小压入元素,队列里当前元素全为大于等于s[i]的
    {                    //优先队列里的是权值小的,优先将权值小的弹出
        sum+=ee[i].v;
        que.push(NN{ee[i].v});
        while(que.size()>ee[i].s)//超出数量弹出
            sum-=que.top().v,que.pop();
        ans=max(ans,sum);
    }
    printf("%lld\n",ans);
    return 0;
}

法2:直接用树状数组二分暴力处理

#include<bits/stdc++.h>
#define lowbit(x) (x)&(-x)
#define ll long long
#define MAXN 100005
using namespace std;
ll s[MAXN],v[MAXN];
vector<ll> vc[MAXN];
ll n;
ll sum[MAXN];
ll num[MAXN];
struct node
{
    ll id,v,s;
    friend bool operator <(node a,node b)
    {
        return a.v>b.v;
    }
}b[MAXN];
 
void add(ll x,ll c)
{
    for(ll i=x;i<=n;i+=lowbit(i))
        sum[i]+=c,num[i]+=1;
}
 
void add2(ll x,ll c)
{
    for(ll i=x;i<=n;i+=lowbit(i))
        sum[i]-=c,num[i]-=1;
}
 
ll query(ll r)
{
    ll ans=0;
    for(ll i=r;i>0;i-=lowbit(i))
        ans+=sum[i];
    return ans;
}
 
ll query2(ll r)
{
    ll ans=0;
    for(ll i=r;i>0;i-=lowbit(i))
        ans+=num[i];
    return ans;
}
 
int main()
{
    scanf("%lld",&n);
    for(ll i=1;i<=n;i++)//每次把小于于s[i]的删除,然后从剩下的里找最大的s[i]个
    {
        scanf("%lld%lld",&v[i],&s[i]);
        b[i]=node{i,v[i],s[i]};
    }
    sort(b+1,b+n+1);
    for(ll i=1;i<=n;i++)
        vc[b[i].s].push_back(i);
 
    for(ll i=1;i<=n;i++)
        add(i,b[i].v);
    ll Res=0;
    for(ll i=1;i<=n;i++)
    {
        if(vc[i].size()==0)
            continue;
        else{
            ll l=1,r=n;
            ll ans=0;
            while(l<=r)
            {
                ll mid=(l+r)>>1;
                ll k=query2(mid);//个数
                if(k<=i)
                {
                    l=mid+1;
                    ans=max(ans,mid);
                }
                else{
                    r=mid-1;
                }
            }
            ll res=query(ans);
            Res=max(res,Res);
            for(ll j=0;j<vc[i].size();j++)
            {
                ll k=vc[i][j];
                add2(k,b[k].v);//位置和值的坐标是反的
            }
        }
    }
    printf("%lld\n",Res);
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值