大一寒假集訓八 優先隊列
合併果子-優先隊列
#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 入隊
加一個判斷,判斷兩數的和有沒有如果隊
此法更省時間,但我現在還實現不了