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 入隊
加一個判斷,判斷兩數的和有沒有如果隊
此法更省時間,但我現在還實現不了

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章