NEFU 优先队列

大一寒假集训八 优先队列

合并果子-优先队列

#include <bits/stdc++.h>
using namespace std;
priority_queue<int,vector<int>,greater<int> >vis;//从小到大排列,固定格式记住就好
int main()
{
    int n;
    cin>>n;
    for(int i=0;i<n;i++)
    {
        int x;
        cin>>x;
        vis.push(x);
    }
    int res=0;
    while(vis.size()>=2)
    {
        int a=vis.top();//优先队列中取出队首元素用top,区别队列中用front
        vis.pop();
        int b=vis.top();
        vis.pop();
        vis.push(a+b);
        res=res+a+b;
    }
    cout<<res<<endl;
    return 0;
}

合成陨石-优先队列

#include <bits/stdc++.h>
using namespace std;
priority_queue<int,vector<int>,greater<int> >vis;//从小到大排列,换成less是从大到小排列
int main()
{
    int n;
    while(cin>>n)
    {
        for(int i=0; i<n; i++)
        {
            int x;
            cin>>x;
            vis.push(x);
        }
        int res=0;
        while(vis.size()>=2)
        {
            int a=vis.top();
            vis.pop();
            int b=vis.top();
            vis.pop();
            vis.push(a+b);
            res=res+a+b;
        }
        cout<<res<<endl;
        vis.pop();//多组输入注意要清空队列
    }
    return 0;
}

买饭-优先队列

#include <bits/stdc++.h>
using namespace std;
struct per
{
    int time;//存买饭时间
    int num;//存编号
};
bool operator < (const per &a,const per &b)//结构体自定义排序
{
    if(a.time!=b.time)
        return a.time>b.time;//与cmp函数相反,> 表示从小到大排列
    else
        return a.num>b.num;
}
priority_queue<per,vector<per> >vis;
int main()
{
    int n;
    cin>>n;
    for(int i=1; i<=n; i++)
    {
        int x;
        cin>>x;
        vis.push({x,i});
    }
    double ans=0,res=0;
    while(!vis.empty())
    {
        int x=vis.top().num;
        int y=vis.top().time;
        vis.pop();//取出队首元素后要立即出队
        res=res+ans;
        ans=ans+y;
        if(vis.empty())//注意输出格式
            cout<<x<<endl;
        else
            cout<<x<<" ";
    }
    printf("%.2lf",res/n);
    return 0;
}

堆-优先队列

#include <bits/stdc++.h>
using namespace std;
priority_queue<int,vector<int>,greater<int> >vis;
int main()
{
    int n;
    cin>>n;
    for(int i=1; i<=n; i++)
    {
        int m;
        cin>>m;
        if(m==1)
        {
            int x;
            cin>>x;
            vis.push(x);
        }
        else if(m==2)
        {
            int res=vis.top();
            cout<<res<<endl;
        }
        else if(m==3)
            vis.pop();
    }
    return 0;
}

瑞瑞的木板-优先队列

对于这道题的一些思考:首先面对这道题的想法是每次砍掉对大的,使用贪心法,但对于此题来说,每次砍掉最大的不一定就是最省的方案,先将板子砍成两段再分别在两段板子中砍有可能出现更省的方案,例如数据:1 2 3 4 5,若先砍最大的5,耗费的力气大于先堪称6和9.
因此使用贪心法要先正确的证明过程最小则结果最小,在此题中是不成立的

#include <bits/stdc++.h>
using namespace std;
priority_queue<int,vector<int>,greater<int> >vis;
int main()
{
    int n;
    cin>>n;
    for(int i=1; i<=n; i++)
    {
        int x;
        cin>>x;
        vis.push(x);
    }
    long long int res=0;
    while(vis.size()>1)
    {
        int a=vis.top();
        vis.pop();
        int b=vis.top();
        vis.pop();
        res=res+a+b;
        vis.push(a+b);
    }
    cout<<res<<endl;
    return 0;
}

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

#include <bits/stdc++.h>
using namespace std;
struct per
{
    int id;
    int time1;
    int time2;
};
bool operator < (const per &a,const per &b)
{
    if(a.time1!=b.time1)
        return a.time1>b.time1;
    else
        return a.id>b.id;
}
priority_queue<per,vector<per> >vis;
int main()
{
    string a;
    for(int i=0;; i++)
    {
        cin>>a;
        if(a[0]=='#')
            break;
        int x,y;
        cin>>x>>y;
        vis.push({x,y,y});
    }
    int k;
    cin>>k;
    while(k>0)
    {
        int res=vis.top().id;
        int mid=vis.top().time1;
        int t=vis.top().time2;
        cout<<res<<endl;
        k--;
        vis.pop();
        vis.push({res,mid+t,t});
    }
    return 0;
}

序列合并-优先队列

思路1:

首先,把A和B两个序列分别从小到大排序,变成两个有序队列。这样,从A和B中各任取一个数相加得到N2个和,可以把这些和看成形成了n个有序表/队列:
A[1]+B[1] <= A[1]+B[2] <= … <= A[1]+B[N]
A[2]+B[1] <= A[2]+B[2] <= … <= A[2]+B[N]
……
A[N]+B[1] <= A[N]+B[2] <= … <= A[N]+B[N]
接下来,就相当于要将这N个有序队列进行合并排序:
首先,将这N个队列中的第一个元素放入一个优先队列中;
然后,每次取出堆中的最小值。若这个最小值来自于第k个队列,那么,就将第k个队列的下一个元素放入堆中。

#include <bits/stdc++.h>
using namespace std;
struct sa
{
    int x1;
    int y1;
    long long int s;
};
bool operator < (const sa &a,const sa &b)
{
    return a.s>b.s;
}
priority_queue<sa,vector<sa> >vis;
long long int x[400050],y[400050];//数组过大定义到里面会出问题
int main()
{
    int n;
    scanf("%d",&n);
    for(int i=1; i<=n; i++)
        scanf("%lld",&x[i]);//scanf比cin要省时间
    for(int i=1; i<=n; i++)
        scanf("%lld",&y[i]);
    for(int i=1; i<=n; i++)
        vis.push({i,1,x[i]+y[1]});
    for(int i=1; i<=n; i++)
    {
        sa t=vis.top();
        vis.pop();
        printf("%d\n",t.s);
        int s1=t.x1;
        int s2=t.y1;
        vis.push({s1,s2+1,x[s1]+y[s2+1]});
    }
    return 0;
}

思路2:

A[1]+B[1] <= A[1]+B[2] <= … <= A[1]+B[N]
A[2]+B[1] <= A[2]+B[2] <= … <= A[2]+B[N]
……
A[N]+B[1] <= A[N]+B[2] <= … <= A[N]+B[N]

从左上角开始按级读入
第一级:A[1]+B[1]
第二级:A[2]+B[1] 和 A[1]+B[2]

以此类推…
每次输出队首元素
然后将队首元素的 A的下标+1,B的下标不变A的下标不变,B的下标+1 入队
加一个判断,判断两数的和有没有如果队
此法更省时间,但我现在还实现不了

猜你喜欢

转载自blog.csdn.net/qq_46126537/article/details/104292412