大一寒假集训八 优先队列
合并果子-优先队列
#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 入队
加一个判断,判断两数的和有没有如果队
此法更省时间,但我现在还实现不了