c++stl之优先队列(priority_queue)

1.大跟堆:从小到大,最小的优先级最高定义方法:

priority_queue<int,vector<int>,greater<int> >vis;

注意vis左边> >这两个">"中间有个空格,不能少

2.小跟堆:从大到小,最大的优先级最高

定义方法:

priority_queue<int>vis;

基本跟队列相同,不同的是:

3.队列返回队头元素front(),优先队列返回优先级最高的元素top()

4.结构体定义方式:

struct sa
{
    int x,num;
};
bool operator<(const sa&a,const sa&b)
{
    if(a.x!=b.x)
        return a.x<b.x;//与平常相反,这里输出大到小排列
    else return a.num<b.num;
}
priority_queue<sa>vis2;

洛谷 P3378 【模板】堆

#include <bits/stdc++.h>
using namespace std;

priority_queue<int,vector<int>,greater<int> >vis;//大根堆从小到大
int a[10005];
int main()//
{
    int n,x,flag;
    while(~scanf("%d",&n))
    for(int i=0;i<n;i++)
    {
        scanf("%d",&flag);
        if(flag==1)
        {
            scanf("%d",&x);
            vis.push(x);
        }
        if(flag==2){cout<<vis.top()<<endl;}
        if(flag==3){vis.pop();}
    }

    return 0;
}

买饭-优先队列

#include <bits/stdc++.h>
using namespace std;
typedef unsigned long long ll;
priority_queue<int>vis;//小根堆从大到小
struct sa
{
    int val,num;
}a[1005];
bool cmp(sa b,sa c)
{
   if(b.val!=c.val)
   return b.val<c.val;
   else return b.num<c.num;
}
int main()//
{
    int n,x,flag;
    long long sum=0;
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&a[i].val);
        a[i].num=i;
        vis.push(a[i].val);
    }
    int cnt1,cnt2;
    sort(a+1,a+n+1,cmp);
    int j=n-1;
    for(int i=1;i<=n;i++)
    {
        sum+=(a[i].val * j);
        j--;
    }
    double r=1.0*sum/n;
    for(int i=1;i<n;i++)
    {
        cout<<a[i].num<<" ";
    }
    cout<<a[n].num<<endl;
    printf("%.2lf",r);
    return 0;
}

P1090 合并果子

#include <bits/stdc++.h>
using namespace std;
typedef unsigned long long ll;
priority_queue<int,vector<int>,greater<int> >vis;//大根堆从小到大
int a[10005];
int main()//
{
    int n,x;
    scanf("%d",&n);
    for(int i=0;i<n;i++)
    {
        scanf("%d",&x);
        vis.push(x);
    }
    int cnt1,cnt2,sum=0;
    while(vis.size()>=2)
    {
        cnt1=vis.top();
        vis.pop();
        cnt2=vis.top();
        vis.pop();
        sum+=(cnt1+cnt2);
        vis.push(cnt1+cnt2);
    }
    cout<<sum<<endl;
    return 0;
}

P1334 瑞瑞的木板

#include <bits/stdc++.h>
using namespace std;
typedef unsigned long long ll;
priority_queue<int,vector<int>,greater<int> >vis;//大根堆从小到大
int a[20005];
int main()//
{
    int n,x,flag;
    long long sum=0;
    scanf("%d",&n);
    for(int i=0;i<n;i++)
    {
        scanf("%d",&x);
        vis.push(x);
    }
    int cnt1,cnt2;
    while(vis.size()>=2)
    {
        cnt1=vis.top();
        vis.pop();
        cnt2=vis.top();
        vis.pop();
        vis.push(cnt1+cnt2);
        sum+=(cnt1+cnt2);
    }
    cout<<sum<<endl;
    return 0;
}

nefu 355 合成陨石-优先队列

#include <bits/stdc++.h>
using namespace std;
typedef unsigned long long ll;
priority_queue<int,vector<int>,greater<int> >vis;//大根堆从小到大
int a[10005];
int main()//
{
    int n,x;
    while(~scanf("%d",&n)){
    for(int i=0;i<n;i++)
    {
        scanf("%d",&x);
        vis.push(x);
    }
    int cnt1,cnt2,sum=0;
    while(vis.size()>=2)
    {
        cnt1=vis.top();
        vis.pop();
        cnt2=vis.top();
        vis.pop();
        sum+=(cnt1+cnt2);
        vis.push(cnt1+cnt2);
    }
    vis.pop();
    cout<<sum<<endl;
    }
    return 0;
}

P1631 序列合并

这种题第一次做确实是没思路,理解了就好做了

思路:1.将两个序列都从小到大排序 2.把第一个序列中第一个数别加上第二个序列中的所有数,放入优先队列中(大根堆)并且标记这个加起来的数是第一个序列第几个数加上第二个序列的第几个数(用结构体)3.输出优先队列顶部的数,并且将第一个序列第二个数加上 输出的这个数的第二个序列的数 放入队列中,依次类推

#include <bits/stdc++.h>
using namespace std;
typedef unsigned long long ll;
struct sa
{
    int x,y;
    ll sum;
}t;
const int N=4e5+5;
bool operator<(const sa &a,const sa &b)
{
    return a.sum>b.sum;//与平常相反,这里输出大到小排列
}
priority_queue<sa,vector<sa> >vis;
int a[N],b[N];
int n;
int main()//
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)scanf("%d",&a[i]);
    for(int i=1;i<=n;i++)scanf("%d",&b[i]);
    for(int i=1;i<=n;i++)
    {
        vis.push({i,1,a[i]+b[1]});
    }
    for(int i=1;i<=n;i++)
    {
        sa tmp=vis.top();vis.pop();
        printf("%lld\n",tmp.sum);
        int x=tmp.x,y=tmp.y;
        vis.push({x,y+1,a[x]+b[y+1]});
    }
    return 0;
}

nefu 1949 库特的绳子

这类题见得少,跟上边那个 序列合并 有点像,都是两个序列,考试的时候就差这个就ak了啊,桑心

贪心思想:将最短的绳子与钉子距离最短的依次比较

解题思路:1.先绳子从小到大排序 2.把钉子位置从小到大排序后,将每一小段都放入优先队列中(大根堆)并且标记左右端点(用结构体)3.比较完了的钉子右端点右移一位

#include <bits/stdc++.h>
using namespace std;

struct sa
{
    int x,y,num;
};
bool operator<(const sa&a,const sa&b)
{

    return a.num>b.num;
}
priority_queue<sa>vis;

const int N=5e5+10;
int a[N],b[N];
int main()
{
    int n,m,t,l;
    while(~scanf("%d %d",&n,&m))
    {
        for(int i=1;i<=n;i++)scanf("%d",&a[i]);
        for(int i=1;i<=m;i++)scanf("%d",&b[i]);//绳子长度
        sort(b+1,b+1+m);sort(a+1,a+1+n);
        sa tmp;
        for(int i=1;i<n;i++)
        {
            vis.push({i,i+1,a[i+1]-a[i]});
        }
        int tx,ty,flag=1;
        for(int i=1;i<=m;i++)
        {
            if (vis.empty()){flag=0;break;}
            tmp=vis.top();vis.pop();
            if(b[i]>=tmp.num)
            {
                tx=tmp.x;
                ty=tmp.y+1;
                if(ty<=n)vis.push({tx,ty,a[ty]-a[tx]});
            }
            else {flag=0;break;}
        }
        if(flag==0)printf("no\n");
        else printf("yes\n");
        while(!vis.empty())vis.pop();
    }
    return 0;
}

nefu 1690 桐桐的新闻系统-优先队列

挺难的

#include <bits/stdc++.h>
using namespace std;
typedef unsigned long long ll;
struct sa
{
    int id,p,val;
}t;
bool operator<(const sa &a,const sa &b)
{
    if(a.val!=b.val)
        return a.val>b.val;//与平常相反,这里输出大到小排列
    return a.id>b.id;
}
priority_queue<sa,vector<sa> >vis;
char s[10];
int main()//
{
    char ch;
    int i=0;
    while(cin>>s&&s[0]!='#')
    {
        cin>>t.id>>t.p;
        vis.push({t.id,t.p,t.p});
    }
    int cnt;
    scanf("%d",&cnt);
    while(cnt--)
    {
        sa tmp=vis.top();//剩余的时间
        vis.pop();
        cout<<tmp.id<<endl;
        vis.push({tmp.id,tmp.p,tmp.val+tmp.p});
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/zhoucheng_123/article/details/104299969