优先队列(3道优先队列问题)

来源:互联网 发布:nginx 线程模型 编辑:程序博客网 时间:2024/06/06 11:42
  1. 优先队列是一种十分强大的数据结构,它保持了一种动态的有序性,对于不断改变有入队的操作,而又需要某种最大或最小的操作的问题是再合适不过了,通常优先队列的实现是由最小堆或者最大堆完成的,并通过堆排序保持队列的有序性,模拟队列的结构,在实际比赛中要写一个堆排序还是要一定的时间的,但是stl中queue容器中已经可以实现优先队列,下面以三道基本的题目来演示priority_queue的作用。  
  2.   
  3. 聪明的木匠    
  4. Time Limit: 1000ms, Special Time Limit: 2500ms, Memory Limit: 32768KB    
  5. Total submit users: 23, Accepted users: 10    
  6. Problem 10611 : No special judgement    
  7. Problem description    
  8.     最近,一位老木匠遇到了一件非常棘手的问题。他需要将一根非常长的木棒切成N 段。每段的长度分别为 L1 ,L2 ,…,LN ( 1≤L1 ,L2 ,…,LN ≤1000 ,且均为整数)个长度单位。 ∑Li (i=1,2,…,N) 恰好就是原木棒的长度。我们认为切割时仅在整数点处切且没有木材损失。   
  9.   木匠发现,每一次切割花费的体力与该木棒的长度成正比,不妨设切割长度为 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 体力。显然,后者比前者更省体力。   
  10.   那么,木匠至少要花费多少体力才能完成切割任务呢?   
  11.   
  12.    
  13. Input    
  14.   输入数据的第一行为一个整数N(2≤N≤150,000) ;   
  15. 在接下来的 N 行中,每行为一个整数 Li (1≤Li ≤1000) 。   
  16.   
  17.    
  18. Output    
  19.   输出数据仅有一行,为一个整数,表示木匠最少要花费的体力。测试数据保证这个整数不大于231 -1 。   
  20.   
  21.    
  22. Sample Input    
  23. 4  
  24. 3  
  25. 5  
  26. 7  
  27. 11  
  28.    
  29. Sample Output    
  30. 49   
  31. Problem Source    
  32.   2010年河北大学程序设计竞赛   
  33.    
  34.   
  35.    
  36.   
  37. 最优的方法是每次切出最小的合并,显然要使用优先队列;  
  38.   
  39. [cpp:firstline[1]] view plaincopyprint?#include <iostream>     
  40. #include <queue>     
  41. struct cmp    
  42. {    
  43.     bool operator ()(const int &i,const int &j)    
  44.     {    
  45.         return i>j;    
  46.     }    
  47. };    
  48. using namespace std;    
  49. int main()    
  50. {    
  51.     priority_queue<int,vector<int>,cmp> s;    
  52.     int n;    
  53.     while(cin>>n)    
  54.     {    
  55.         for(int i=0;i<n;i++)    
  56.         {    
  57.             int key;    
  58.             scanf("%d",&key);    
  59.             s.push(key);    
  60.         }    
  61.         int sum=0;    
  62.         while(n>=2)    
  63.         {    
  64.             int a,b;    
  65.             a=s.top();    
  66.             s.pop();    
  67.             b=s.top();    
  68.             s.pop();    
  69.             s.push(a+b);    
  70.             //cout<<a<<' '<<b;     
  71.             sum+=a+b;    
  72.             n--;    
  73.         }    
  74.         cout<<sum<<endl;    
  75.     }    
  76.     return 0;    
  77.         
  78. }    
  79. #include <iostream>  
  80. #include <queue>  
  81. struct cmp  
  82. {  
  83.     bool operator ()(const int &i,const int &j)  
  84.     {  
  85.         return i>j;  
  86.     }  
  87. };  
  88. using namespace std;  
  89. int main()  
  90. {  
  91.     priority_queue<int,vector<int>,cmp> s;  
  92.     int n;  
  93.     while(cin>>n)  
  94.     {  
  95.         for(int i=0;i<n;i++)  
  96.         {  
  97.             int key;  
  98.             scanf("%d",&key);  
  99.             s.push(key);  
  100.         }  
  101.         int sum=0;  
  102.         while(n>=2)  
  103.         {  
  104.             int a,b;  
  105.             a=s.top();  
  106.             s.pop();  
  107.             b=s.top();  
  108.             s.pop();  
  109.             s.push(a+b);  
  110.             //cout<<a<<' '<<b;  
  111.             sum+=a+b;  
  112.             n--;  
  113.         }  
  114.         cout<<sum<<endl;  
  115.     }  
  116.     return 0;  
  117.       
  118. }  
  119.    
  120.   
  121.    
  122.   
  123. 【问题描述】  
  124. 在一个果园里,多多已经将所有的果子打了下来,而且按果子的不同种类分成了不同的堆。多多决定把所有的果子合成一堆。每一次合并,多多可以把两堆果子合并到一起,消耗的体力等于两堆果子的重量之和。可以看出,所有的果子经过n-1次合并之后,就只剩下一堆了。多多在合并果子时总共消耗的体力等于每次合并所耗体力之和。  
  125. 因为还要花大力气把这些果子搬回家,所以多多在合并果子时要尽可能地节省体力。假定每个果子重量都为1,并且已知果子的种类数和每种果子的数目,你的任务是设计出合并的次序方案,使多多耗费的体力最少,并输出这个最小的体力耗费值。  
  126. 例如有3种果子,数目依次为1,2,9。可以先将 1、2堆合并,新堆数目为3,耗费体力为3。接着,将新堆与原先的第三堆合并,又得到新的堆,数目为12,耗费体力为 12。所以多多总共耗费体力=3+12=15。可以证明15为最小的体力耗费值。  
  127. 【输入文件】  
  128. 输入文件fruit.in包括两行,第一行是一个整数n(1 <= n <= 10000),表示果子的种类数。第二行包含n个整数,用空格分隔,第i个整数ai(1 <= ai <= 20000)是第i种果子的数目。  
  129. 【输出文件】  
  130. 输出文件fruit.out包括一行,这一行只包含一个整数,也就是最小的体力耗费值。输入数据保证这个值小于231。  
  131. 【样例输入】  
  132. 3  
  133. 1 2 9  
  134. 【样例输出】  
  135. 15  
  136. 【数据规模】  
  137. 对于30%的数据,保证有n <= 1000;  
  138. 对于50%的数据,保证有n <= 5000;  
  139. 对于全部的数据,保证有n <= 10000。   
  140.   
  141.    
  142.   
  143. 合并的最优方法是合并最小的两堆,通过优先队列就可以轻松实现;  
  144.   
  145. [cpp:firstline[1]] view plaincopyprint?#include <iostream>     
  146. #include <queue>     
  147. struct cmp    
  148. {    
  149.     bool operator ()(const int &i,const int &j)    
  150.     {    
  151.         return i>j;    
  152.     }    
  153. };    
  154. using namespace std;    
  155. int main()    
  156. {    
  157.     priority_queue<int,vector<int>,cmp> s;    
  158.     int n;    
  159.     while(cin>>n)    
  160.     {    
  161.         for(int i=0;i<n;i++)    
  162.         {    
  163.             int key;    
  164.             scanf("%d",&key);    
  165.             s.push(key);    
  166.         }    
  167.         int sum=0;    
  168.         while(n>=2)    
  169.         {    
  170.             int a,b;    
  171.             a=s.top();    
  172.             s.pop();    
  173.             b=s.top();    
  174.             s.pop();    
  175.             s.push(a+b);    
  176.             //cout<<a<<' '<<b;     
  177.             sum+=a+b;    
  178.             n--;    
  179.         }    
  180.         cout<<sum<<endl;    
  181.     }    
  182.     return 0;    
  183.         
  184. }    
  185. #include <iostream>  
  186. #include <queue>  
  187. struct cmp  
  188. {  
  189.     bool operator ()(const int &i,const int &j)  
  190.     {  
  191.         return i>j;  
  192.     }  
  193. };  
  194. using namespace std;  
  195. int main()  
  196. {  
  197.     priority_queue<int,vector<int>,cmp> s;  
  198.     int n;  
  199.     while(cin>>n)  
  200.     {  
  201.         for(int i=0;i<n;i++)  
  202.         {  
  203.             int key;  
  204.             scanf("%d",&key);  
  205.             s.push(key);  
  206.         }  
  207.         int sum=0;  
  208.         while(n>=2)  
  209.         {  
  210.             int a,b;  
  211.             a=s.top();  
  212.             s.pop();  
  213.             b=s.top();  
  214.             s.pop();  
  215.             s.push(a+b);  
  216.             //cout<<a<<' '<<b;  
  217.             sum+=a+b;  
  218.             n--;  
  219.         }  
  220.         cout<<sum<<endl;  
  221.     }  
  222.     return 0;  
  223.       
  224. }  
  225.    
  226.   
  227.    
  228.   
  229. 删除最小值    
  230. Time Limit: 1000ms, Special Time Limit: 2500ms, Memory Limit: 32768KB    
  231. Total submit users: 8, Accepted users: 8    
  232. Problem 10604 : No special judgement    
  233. Problem description    
  234.   序列A 中有 N 个元素,序列 B 中也有 N 个元素,依次将序列 B 中的元素移进序列 A ,对于每次移进元素,首先在一行输出序列 A 中的最小值,然后在 A 在加入该元素,接着在序列 B 中删除该元素,接着在序列 A 中删除刚才输出的最小值。  
  235.   
  236.    
  237. Input    
  238.   共三行,第一行给出元素数目N ,第二行给出 A 中的原始 N 个元素,第三行给出 B 中的原始 N 个元素。 1 ≤ n ≤ 10000 ,每个元素值范围为 [0 , 100000] 。  
  239.   
  240.    
  241. Output    
  242.   在每次将B中的元素移入A之前,在一行里输出A中所有元素的最小值。  
  243.   
  244.    
  245. Sample Input    
  246. 3  
  247. 3 9 6  
  248. 5 2 10  
  249.    
  250. Sample Output    
  251. 3  
  252. 5  
  253. 2  
  254.    
  255.   
  256. 这道题目跟到模拟题目差不多……  
  257.   
  258. [cpp:firstline[1]] view plaincopyprint?#include <iostream>     
  259. #include <queue>     
  260. struct cmp    
  261. {    
  262.     bool operator ()(const int &i,const int &j)    
  263.     {    
  264.         return i>j;    
  265.     }    
  266. };    
  267. using namespace std;    
  268. int main()    
  269. {    
  270.     int b[10003];    
  271.     priority_queue<int,vector<int>,cmp> s;    
  272.     int n;    
  273.     while(cin>>n)    
  274.     {    
  275.         for(int i=0;i<n;i++)    
  276.         {    
  277.             int key;    
  278.             scanf("%d",&key);    
  279.             s.push(key);    
  280.                 
  281.         }    
  282.         for(int i=0;i<n;i++)    
  283.         {    
  284.             scanf("%d",&b[i]);    
  285.         }    
  286.         for(int j=0;j<n;j++)    
  287.         {    
  288.                 
  289.             //cout<<b[j]<<endl;     
  290.             printf("%d/n",s.top());    
  291.             s.pop();    
  292.             s.push(b[j]);    
  293.                 
  294.         }    
  295.             
  296.      }    
  297.     return 0;    
  298.         
  299. }    
  300. #include <iostream>  
  301. #include <queue>  
  302. struct cmp  
  303. {  
  304.     bool operator ()(const int &i,const int &j)  
  305.     {  
  306.         return i>j;  
  307.     }  
  308. };  
  309. using namespace std;  
  310. int main()  
  311. {  
  312.     int b[10003];  
  313.     priority_queue<int,vector<int>,cmp> s;  
  314.     int n;  
  315.     while(cin>>n)  
  316.     {  
  317.         for(int i=0;i<n;i++)  
  318.         {  
  319.             int key;  
  320.             scanf("%d",&key);  
  321.             s.push(key);  
  322.               
  323.         }  
  324.         for(int i=0;i<n;i++)  
  325.         {  
  326.             scanf("%d",&b[i]);  
  327.         }  
  328.         for(int j=0;j<n;j++)  
  329.         {  
  330.               
  331.             //cout<<b[j]<<endl;  
  332.             printf("%d/n",s.top());  
  333.             s.pop();  
  334.             s.push(b[j]);  
  335.               
  336.         }  
  337.           
  338.      }  
  339.     return 0;  
  340.       
  341. }  
  342.    
  343.   
  344. 以上三道题目如果掌握优先队列再去解答十分简单,做这种优先队列的题目,如果发现是使用优先队列的就很简单了(说的这都是废话!)  
  345.   
  346. stl中的优先队列的模板:  
  347.   
  348. #include <queue>  
  349.   
  350. priority_queue <int> q;  
  351.   
  352. 这是按照从大到小的队列;  
  353.   
  354. #include <queue>  
  355.   
  356. struct cmp  
  357.   
  358. {  
  359.   
  360.     bool operator ()(const int &i,const int &j)  
  361.   
  362.     {  
  363.   
  364.         return i>j;  
  365.   
  366.     }  
  367.   
  368. };  
  369.   
  370. priority_queue <int> q;  
  371.   
  372. 这是从小到大的优先队列;  
0 0