- 优先队列是一种十分强大的数据结构,它保持了一种动态的有序性,对于不断改变有入队的操作,而又需要某种最大或最小的操作的问题是再合适不过了,通常优先队列的实现是由最小堆或者最大堆完成的,并通过堆排序保持队列的有序性,模拟队列的结构,在实际比赛中要写一个堆排序还是要一定的时间的,但是stl中queue容器中已经可以实现优先队列,下面以三道基本的题目来演示priority_queue的作用。
- 聪明的木匠
- Time Limit: 1000ms, Special Time Limit: 2500ms, Memory Limit: 32768KB
- Total submit users: 23, Accepted users: 10
- Problem 10611 : No special judgement
- Problem description
- 最近,一位老木匠遇到了一件非常棘手的问题。他需要将一根非常长的木棒切成N 段。每段的长度分别为 L1 ,L2 ,…,LN ( 1≤L1 ,L2 ,…,LN ≤1000 ,且均为整数)个长度单位。 ∑Li (i=1,2,…,N) 恰好就是原木棒的长度。我们认为切割时仅在整数点处切且没有木材损失。
- 木匠发现,每一次切割花费的体力与该木棒的长度成正比,不妨设切割长度为 1 的木棒花费 1 单位体力。例如,若 N=3 , L1 =3,L2 =4,L3 =5 ,则木棒原长为 12 ,木匠可以有多种切法,如:先将 12 切成 3+9. ,花费 12 体力,再将 9 切成 4+5 ,花费 9 体力,一共花费 21 体力;还可以先将 12 切成 4+8 ,花费 12 体力,再将 8 切成 3+5 ,花费 8 体力,一共花费 20 体力。显然,后者比前者更省体力。
- 那么,木匠至少要花费多少体力才能完成切割任务呢?
- Input
- 输入数据的第一行为一个整数N(2≤N≤150,000) ;
- 在接下来的 N 行中,每行为一个整数 Li (1≤Li ≤1000) 。
- Output
- 输出数据仅有一行,为一个整数,表示木匠最少要花费的体力。测试数据保证这个整数不大于231 -1 。
- Sample Input
- 4
- 3
- 5
- 7
- 11
- Sample Output
- 49
- Problem Source
- 2010年河北大学程序设计竞赛
- 最优的方法是每次切出最小的合并,显然要使用优先队列;
- [cpp:firstline[1]] view plaincopyprint?#include <iostream>
- #include <queue>
- struct cmp
- {
- bool operator ()(const int &i,const int &j)
- {
- return i>j;
- }
- };
- using namespace std;
- int main()
- {
- priority_queue<int,vector<int>,cmp> s;
- int n;
- while(cin>>n)
- {
- for(int i=0;i<n;i++)
- {
- int key;
- scanf("%d",&key);
- s.push(key);
- }
- int sum=0;
- while(n>=2)
- {
- int a,b;
- a=s.top();
- s.pop();
- b=s.top();
- s.pop();
- s.push(a+b);
- //cout<<a<<' '<<b;
- sum+=a+b;
- n--;
- }
- cout<<sum<<endl;
- }
- return 0;
- }
- #include <iostream>
- #include <queue>
- struct cmp
- {
- bool operator ()(const int &i,const int &j)
- {
- return i>j;
- }
- };
- using namespace std;
- int main()
- {
- priority_queue<int,vector<int>,cmp> s;
- int n;
- while(cin>>n)
- {
- for(int i=0;i<n;i++)
- {
- int key;
- scanf("%d",&key);
- s.push(key);
- }
- int sum=0;
- while(n>=2)
- {
- int a,b;
- a=s.top();
- s.pop();
- b=s.top();
- s.pop();
- s.push(a+b);
- //cout<<a<<' '<<b;
- sum+=a+b;
- n--;
- }
- cout<<sum<<endl;
- }
- return 0;
- }
- 【问题描述】
- 在一个果园里,多多已经将所有的果子打了下来,而且按果子的不同种类分成了不同的堆。多多决定把所有的果子合成一堆。每一次合并,多多可以把两堆果子合并到一起,消耗的体力等于两堆果子的重量之和。可以看出,所有的果子经过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。
- 合并的最优方法是合并最小的两堆,通过优先队列就可以轻松实现;
- [cpp:firstline[1]] view plaincopyprint?#include <iostream>
- #include <queue>
- struct cmp
- {
- bool operator ()(const int &i,const int &j)
- {
- return i>j;
- }
- };
- using namespace std;
- int main()
- {
- priority_queue<int,vector<int>,cmp> s;
- int n;
- while(cin>>n)
- {
- for(int i=0;i<n;i++)
- {
- int key;
- scanf("%d",&key);
- s.push(key);
- }
- int sum=0;
- while(n>=2)
- {
- int a,b;
- a=s.top();
- s.pop();
- b=s.top();
- s.pop();
- s.push(a+b);
- //cout<<a<<' '<<b;
- sum+=a+b;
- n--;
- }
- cout<<sum<<endl;
- }
- return 0;
- }
- #include <iostream>
- #include <queue>
- struct cmp
- {
- bool operator ()(const int &i,const int &j)
- {
- return i>j;
- }
- };
- using namespace std;
- int main()
- {
- priority_queue<int,vector<int>,cmp> s;
- int n;
- while(cin>>n)
- {
- for(int i=0;i<n;i++)
- {
- int key;
- scanf("%d",&key);
- s.push(key);
- }
- int sum=0;
- while(n>=2)
- {
- int a,b;
- a=s.top();
- s.pop();
- b=s.top();
- s.pop();
- s.push(a+b);
- //cout<<a<<' '<<b;
- sum+=a+b;
- n--;
- }
- cout<<sum<<endl;
- }
- return 0;
- }
- 删除最小值
- Time Limit: 1000ms, Special Time Limit: 2500ms, Memory Limit: 32768KB
- Total submit users: 8, Accepted users: 8
- Problem 10604 : No special judgement
- Problem description
- 序列A 中有 N 个元素,序列 B 中也有 N 个元素,依次将序列 B 中的元素移进序列 A ,对于每次移进元素,首先在一行输出序列 A 中的最小值,然后在 A 在加入该元素,接着在序列 B 中删除该元素,接着在序列 A 中删除刚才输出的最小值。
- Input
- 共三行,第一行给出元素数目N ,第二行给出 A 中的原始 N 个元素,第三行给出 B 中的原始 N 个元素。 1 ≤ n ≤ 10000 ,每个元素值范围为 [0 , 100000] 。
- Output
- 在每次将B中的元素移入A之前,在一行里输出A中所有元素的最小值。
- Sample Input
- 3
- 3 9 6
- 5 2 10
- Sample Output
- 3
- 5
- 2
- 这道题目跟到模拟题目差不多……
- [cpp:firstline[1]] view plaincopyprint?#include <iostream>
- #include <queue>
- struct cmp
- {
- bool operator ()(const int &i,const int &j)
- {
- return i>j;
- }
- };
- using namespace std;
- int main()
- {
- int b[10003];
- priority_queue<int,vector<int>,cmp> s;
- int n;
- while(cin>>n)
- {
- for(int i=0;i<n;i++)
- {
- int key;
- scanf("%d",&key);
- s.push(key);
- }
- for(int i=0;i<n;i++)
- {
- scanf("%d",&b[i]);
- }
- for(int j=0;j<n;j++)
- {
- //cout<<b[j]<<endl;
- printf("%d/n",s.top());
- s.pop();
- s.push(b[j]);
- }
- }
- return 0;
- }
- #include <iostream>
- #include <queue>
- struct cmp
- {
- bool operator ()(const int &i,const int &j)
- {
- return i>j;
- }
- };
- using namespace std;
- int main()
- {
- int b[10003];
- priority_queue<int,vector<int>,cmp> s;
- int n;
- while(cin>>n)
- {
- for(int i=0;i<n;i++)
- {
- int key;
- scanf("%d",&key);
- s.push(key);
- }
- for(int i=0;i<n;i++)
- {
- scanf("%d",&b[i]);
- }
- for(int j=0;j<n;j++)
- {
- //cout<<b[j]<<endl;
- printf("%d/n",s.top());
- s.pop();
- s.push(b[j]);
- }
- }
- return 0;
- }
- 以上三道题目如果掌握优先队列再去解答十分简单,做这种优先队列的题目,如果发现是使用优先队列的就很简单了(说的这都是废话!)
- stl中的优先队列的模板:
- #include <queue>
- priority_queue <int> q;
- 这是按照从大到小的队列;
- #include <queue>
- struct cmp
- {
- bool operator ()(const int &i,const int &j)
- {
- return i>j;
- }
- };
- priority_queue <int> q;
- 这是从小到大的优先队列;
优先队列(3道优先队列问题)
最新推荐文章于 2024-05-01 11:40:32 发布