3道经典的优先队列题(附优先队列的模板)
2015-07-31 21:17
344 查看
优先队列是一种十分强大的数据结构,它保持了一种动态的有序性,对于不断改变有入队的操作,而又需要某种最大或最小的操作的问题是再合适不过了,通常优先队列的实现是由最小堆或者最大堆完成的,并通过堆排序保持队列的有序性,模拟队列的结构,在实际比赛中要写一个堆排序还是要一定的时间的,但是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; 这是从小到大的优先队列;
转自:http://blog.csdn.net/south__wind/article/details/7929785
相关文章推荐
- 在网上找来的几个大牛,忽然觉得自己来参加ACM倒也不是一件错误的事情,梦想总是要有的,万一成了呢。
- 优先队列和普通队列的小小不同
- POJ 1328:Radar Installation 【贪心】
- PAT (Advanced Level) 1096. Consecutive Factors (20) 连续质因数
- 循环
- 嵌入式系统的开发(飞凌6410板)步骤
- 黑马程序员-C语言指针用法
- css页面布局基础
- POJ 1328 Radar Installation【贪心】
- (最短路)dijkstra算法理解
- virtualbox 在window10上的兼容性调整
- 面试准备---Java异常
- poj 1328 && nyoj 287 Radar Installation【贪心】
- 今年暑假不AC
- 【Struts2框架】(一)原理分析
- 黑马程序员-C语言const关键字的使用小结
- mac上的http请求监控软件
- 数字图像学习3
- 方法的重写和重载
- 今年暑假不AC