优先队列练习总结
1、合并果子
(fruit.pas/dpr/c/cpp)
【问题描述】
在一个果园里,多多已经将所有的果子打了下来,而且按果子的不同种类分成了不同的堆。多多决定把所有的果子合成一堆。
每一次合并,多多可以把两堆果子合并到一起,消耗的体力等于两堆果子的重量之和。可以看出,所有的果子经过n-1次合并之后,就只剩下一堆了。多多在合并果子时总共消耗的体力等于每次合并所耗体力之和。
因为还要花大力气把这些果子搬回家,所以多多在合并果子时要尽可能地节省体力。假定每个果子重量都为1,并且已知果子的种类数和每种果子的数目,你的任务是设计出合并的次序方案,使多多耗费的体力最少,并输出这个最小的体力耗费值。
例如有3种果子,数目依次为1,2,9。可以先将1、2堆合并,新堆数目为3,耗费体力为3。接着,将新堆与原先的第三堆合并,又得到新的堆,数目为12,耗费体力为12。所以多多总共耗费体力=3+12=15。可以证明15为最小的体力耗费值。
【输入文件】
输入文件fruit.in包括两行,第一行是一个整数n(1<=n<=10000),表示果子的种类数。第二行包含n个整数,用空格分隔,第i个整数ai(1<=ai<=20000)是第i种果子的数目。
【输出文件】
输出文件fruit.out包括一行,这一行只包含一个整数,也就是最小的体力耗费值。输入数据保证这个值小于231。
【样例输入】
3
1 2 9
【样例输出】
15
【数据规模】
对于30%的数据,保证有n<=1000:
对于50%的数据,保证有n<=5000;
对于全部的数据,保证有n<=10000。
2、最小函数值(minval)
【题目描述】
有n个函数,分别为F1,F2,...,Fn,定义Fi(x)=Aix2+Bix+Ci(x∈N∗(N*代表不含0的自然数)Fi(x)=Ai*x^2+Bi*x+Ci(x∈N∗)。给定这些Ai、Bi和Ci,请求出所有函数的所有函数值中最小的m个(如有重复的要输出多个)。
【输入】
第一行输入两个正整数n和m。
以下n行每行三个正整数,其中第i行的三个数分别位Ai、Bi和Ci。输入数据保证Ai≤10,Bi≤100,Ci≤10000,Ai≤10,Bi≤100,Ci≤10000。
【输出】
将这n个函数所有可以生成的函数值排序后的前m个元素。这m个数应该输出到一行,用空格隔开。
【输入样例】
3 10
4 5 3
3 4 5
1 7 1
【输出样例】
9 12 12 19 25 29 31 44 45 54
【提示】
【数据规模】
n,m≤10000n,m≤10000。
3、看病(hp.cpp)
【题目描述】
有个朋友在医院工作,想请BSNY帮忙做个登记系统。具体是这样的,最近来医院看病的人越来越多了,因此很多人要排队,只有当空闲时放一批病人看病。但医院的排队不同其他排队,因为多数情况下,需要病情严重的人优先看病,所以希望BSNY设计系统时,以病情的严重情况作为优先级,判断接下来谁可以去看病。
【输入】
第一行输入n,表示有n个操作。
对于每个操作,首先输入push或pop。
push的情况,之后会输入ai 和 bi,分别表示患者姓名和患者病情优先级。
pop后面没有输入,但需要你输出。
【输出】
对于pop的操作,输出此时还在排队人中,优先级最大的患者姓名和优先级。
表示他可以进去看病了。
如果此时没人在排队,那么输出”none”,具体可见样例。
【输入样例】
7
pop
push bob 3
push tom 5
push ella 1
pop
push zkw 4
pop
【输出样例】
none
tom 5
zkw 4
【提示】
【数据规模和约定】
1≤n≤100000,每个人的优先级都不一样,0≤优先级≤2000000000。
姓名都是小写字母组成的,长度小于20。
4、小明的账单(bill)
【题目描述】
小明在一次聚会中,不慎遗失了自己的钱包,在接下来的日子,面对小明的将是一系列的补卡手续和堆积的账单… 在小明的百般恳求下,老板最终同意延缓账单的支付时间。可老板又提出,必须从目前还没有支付的所有账单中选出面额最大和最小的两张,并把他们付清。还没有支付的账单会被保留到下一天。 请你帮他计算出支付的顺序。
【输入】
第1行:一个正整数N(N≤15,000),表示小明补办银联卡总共的天数。
第2行到第N+1 行:每一行描述一天中收到的帐单。先是一个非负整数M≤100,表示当天收到的账单数,后跟M个正整数(都小于1,000,000,000),表示每张帐单的面额。
输入数据保证每天都可以支付两张帐单。
【输出】
输出共N 行,每行两个用空格分隔的整数,分别表示当天支付的面额最小和最大的支票的面额。
【输入样例】
4
3 3 6 5
2 8 2
3 7 1 7
0
【输出样例】
3 6
2 8
1 7
5 7
5、踢石头(stone)
问题描述
编程集训,真累人!
课间,某君在操场上沿着笔直的跑道从左往右走着、散步休息……
看到有N个排成一直线的小石头,于是他无聊的踢了起来:
在他遇到第“奇数”块石头时,他会将其往前面踢,能踢多远在输入中会给出,而遇到第“偶数”个石头时不进行处理(不踢:略过)。当有多个石头在同一位置时,则先处理“射程”(踢下,石头往前移的距离)最短的石头。
然后他就这么一直往前走,边走边踢,直到前面已经没有任何石头时,这时候计算该群与出发点的距离。
输入
第一行一个正整数N (0<N<=100,000),表示石头的个数
接下来有N行,每行两个整数,分别表示石头的位置Pi及其射程Di。Pi(0<=Pi<=100,000) 、Di(0<=Di<=1,000)
输出
前面没石头时,离出发点的距离
输入样例一
2
1 5
2 4
输出样例一
11
样例一解析
一开始的时候遇到的是第一个石头(1,5),他的坐标是1,然后往前踢了5个单位之后,坐标变成(6,5)
随后继续往前走,开始遇到第二个石头(2,4),忽略过。
然后继续往前走,遇到了第三个石头(6,5),即原第一个石头,但是它此时坐标为6。往前踢了5个单位之后,坐标变成(11,5),
继续往前走,一直走到坐标11时,遇到第四个石头(11,5),忽略。
前面已经没有石头了,因此此时离坐标原点的距离为11。
输入样例二
2
1 5
6 6
输出样例二
12
数据规模
在90%的数据中,1 ≤ N ≤ 3000;
在100%的数据中,1 ≤ N ≤ 100000;
保证所有输入数据中等级的值小于10^8,1 ≤ K ≤ N-1 。
6、黑匣子(blackbox)
问题描述
Black Box是一种原始的数据库。它可以存储一个整数数组,还有一个特别的变量i。最开始的时候Black Box是空的,而i等于0。这个Black Box要处理一串命令。
命令只有两种:
ADD(x):把x元素放进Black Box;
GET:i加1,然后输出Black Box中第i小的数。
记住:第i小的数,就是Black Box里的数按从小到大的顺序排序后的第i个元素。
例如: 我们来演示一下一个有11个命令的命令串。(如下图所示)
现在要求找出对于给定的命令串的最好的处理方法。ADD和GET命令分别最多有200000个。
现在用两个整数数组来表示命令串:
1、A(1),A(2),…A(M):一串将要被放进Black Box的元素。每个数都是绝对不超过2000000000的整数,M≤200000。例如上面的例子就是
A=(3,1,-4,2,8,-1000,2)。
2、u(1),u(2),…u(N):表示第u(j)个元素被放进了Black Box里后就出现了一个GET命令。例如上面的例子中的u=(1,2,6,6)。
输入数据不用判错。
输入
第一行,两个整数,M,N。
第二行,M个整数,表示A(1) …A(M)。
第三行,N个整数,表示u(1)…u(N)。
输出
输出Black Box根据命令串所得出的输出串,一个数字一行。
输入样例
7 4
3 1 -4 2 8 -1000 2
1 2 6 6
输出样例
3
3
1
2
数据说明
对于30%的数据,M≤10000;
对于50%的数据,M≤100000
对于100%的数据,M≤200000
7、鱼塘钓鱼(fishing)
【题目描述】
有N个鱼塘排成一排(N<100),每个鱼塘中有一定数量的鱼,N=5时,如下表:
第1分钟能钓到的鱼的数量(1..1000) 每过1分钟钓鱼数的减少量(1..100) 当前鱼塘到下一个相邻鱼塘需要的时间( 单位:分钟)
1 10 2 3
2 14 4 5
3 20 6 4
4 16 5 4
5 9 3
即:在第1个鱼塘中钓鱼第1分钟内可钓到10条鱼,第2分钟内只能钓到8条鱼,……,第5分钟以后再也钓不到鱼了。从第1个鱼塘到第2个鱼塘需要3分钟,从第2个鱼塘到第3个鱼塘需要5分钟,……
给出一个截止时间T(T<1000),设计一个钓鱼方案,从第1个鱼塘出发,希望能钓到最多的鱼。假设能钓到鱼的数量仅和已钓鱼的次数有关,且每次钓鱼的时间都是整数分钟。
Input
输入有多组数据,每组数据共5行,分别表示:
第1行为N;
第2行为第1分钟各个鱼塘能钓到的鱼的数量,每个数据之间用一空格隔开;
第3行为每过1分钟各个鱼塘钓鱼数的减少量,每个数据之间用一空格隔开;
第4行为当前鱼塘到下一个相邻鱼塘需要的时间;
第5行为截止时间T;
Output
对于每组数据仅输出一个整数(不超过2^31-1),表示你的方案能钓到的最多的鱼。
Sample Input
5
10 14 20 16 9
2 4 6 5 3
3 5 4 4
14
Sample Output
76
T1~T5都是水题,代码直接贴上虽然说t2看不懂
T1
#include <cstdio>
#include <queue>
using namespace std;
priority_queue<int> Q;
int n,xs;
int main()
{
freopen("fruit.in","r",stdin);
freopen("fruit.out","w",stdout);
scanf("%d",&n);
for(int i=1; i<=n; i++)
{
scanf("%d",&xs);
Q.push(-xs);
}int ans=0;
while(Q.size())
{
int x=-Q.top();Q.pop();
if(!Q.size())break;
int y=-Q.top();Q.pop();
ans+=x+y;
Q.push(-(x+y));
}
printf("%d",ans);
}
T3
#include <iostream>
#include <cstdio>
#include <queue>
using namespace std;
struct node
{
string n;int w;
bool operator < (const node &rhs)const{
return w<rhs.w;
}
};
int n;
priority_queue<node> Q;
int main()
{
freopen("hp.in","r",stdin);
freopen("hp.out","w",stdout);
cin>>n;
while(n--)
{
string x,a;
int y;
cin>>a;
if(a=="pop")
{
if(Q.size())
cout<<Q.top().n<<" "<<Q.top().w<<"\n",Q.pop();
else
cout<<"none\n";
}
else
{
cin>>x>>y;
Q.push({x,y});
}
}
return 0;
}
T4
#include <bits/stdc++.h>
inline void read(int& x) {
x=0;
char ch=0;
bool sign=false;
while(!isdigit(ch)){ sign|=(ch=='-');ch=getchar();}
while(isdigit(ch)) { x=x*10+(ch^48); ch=getchar();}
x=sign?-x:x;
}
using namespace std;
int n,m;
map<long long,int> vis;
priority_queue<int> Q1,Q2;
int x;
int main()
{
freopen("bill.in","r",stdin);
freopen("bill.out","w",stdout);
read(n);
for(int i=1; i<=n; i++)
{
read(m);
for(int i=1; i<=m; i++)
{
int x;
read(x);
Q1.push(x);Q2.push(-x);
}
printf("%d %d\n",-Q2.top(),Q1.top());
Q2.pop();Q1.pop();
}
return 0;
}
T5
#include <cstdio>
#include <cctype>
#include <queue>
struct kl
{
int p,d;
bool operator < (const kl & rhs)const{
return p>rhs.p||p == rhs.p && d>rhs.d;
}
};
std::priority_queue<kl> P;
inline void read(int& x) {
x=0;
char ch=0;
bool sign=false;
while(!isdigit(ch)){ sign|=(ch=='-');ch=getchar();}
while(isdigit(ch)) { x=x*10+(ch^48); ch=getchar();}
x=sign?-x:x;
}
int n;
int x,y;
int ans;
int sum;
int main()
{
freopen("stone.in","r",stdin);
freopen("stone.out","w",stdout);
read(n);
for(int i=1; i<=n; i++)
{
read(x);read(y);
P.push({x,y});
}
while(!P.empty())
{
kl temp=P.top();
ans=temp.p;
P.pop();
sum++;
if((sum%2))
{
P.push({temp.p+temp.d,temp.d});
}
else
{
continue;
}
}
printf("%d",ans);
return 0;
}
T5只打了个暴力,50分。
#include <iostream>
#include <cstdio>
#include <cctype>
#include <queue>
struct node
{
int x;
bool operator < (const node & rhs)const
{
return x>rhs.x;
}
};
int n,m;
int num;
int a[200010];
inline void solve(int x)
{
std::priority_queue<node> temp;
for(int i=1; i<=x; i++)
{
//Q.push(-a[i]);
temp.push({a[i]});
}
num++;
int Temp=num-1;
//printf("num=%d\n",Temp);
for(int i=1; i<=Temp; i++)
{
temp.pop();
}
printf("%d\n",temp.top().x);
}
int main()
{
freopen("blackbox.in","r",stdin);
freopen("blackbox.out","w",stdout);
int x;
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",&x);
solve(x);
}
return 0;
}
正解
尚未理解,待填坑
建立两个优先队列:最大堆a和最小堆b。最大堆a存放前i大的元素,最小堆b存放其它元素,且a.top()<=b.top() 。即每次输出最大堆a的队首元素。 进队:若当前序列的元素比最大堆a的队首元素小,则插入最大堆a,同时为了维护个数,把a的队首元素“移入”最小堆b。否则进入插入最小堆b。 时刻保持最大堆a元素个数与GET操作相对应,即可。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<cstring>
using namespace std;
priority_queue< int , vector<int> , less<int> >q1;
priority_queue< int , vector<int> , greater<int> >q2;
int num[200010],ord[200010],p[200010];
int m,n;
inline int read(){
char ch=getchar(); int rt,ck=1;
while (ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
if (ch=='-'){
ck=-1;
ch=getchar();
}
rt=ch-'0'; ch=getchar();
while (ch>='0'&&ch<='9'){
(rt*=10)+=(ch-'0');
ch=getchar();
}
return rt*ck;
}
int main(){
int j=1,k;
freopen("blackbox.in","r",stdin);
freopen("blackbox.out","w",stdout);
m=read(); n=read();
for (int i=1;i<=m;i++) num[i]=read();
for (int i=1;i<=n;i++) ord[i]=read();
for (int i=1;i<=m;i++){
if (!q1.empty()&&num[i]<q1.top()){
q1.push(num[i]);
q2.push(q1.top());
q1.pop();
}
else{
q2.push(num[i]);
}
while (i==ord[j]){
q1.push(q2.top());
printf("%d\n",q1.top());
j++;
q2.pop();
}
}
return 0;
}
T6还没做