【優先隊列】-HDU4546比賽難度

比賽難度

Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others)
Total Submission(s): 817    Accepted Submission(s): 296


ios

Problem Description
  最近,小明出了一些ACM編程題,決定在HDOJ舉行一場公開賽。
  假設題目的數量一共是n道,這些題目的難度被評級爲一個不超過1000的非負整數,而且一場比賽至少須要一個題,而這場比賽的難度,就是全部題目的難度之和,同時,咱們認爲一場比賽與本場題目的順序無關,並且題目也不會重複。
  顯而易見,很容易獲得以下信息:
  假設比賽只用1個題目,有n種方案;
  假設比賽使用2個題目,有(n-1)*n/2種方案;
  假設比賽使用3個題目,有(n-2)*(n-1)*n/6種方案;
  ............
  假設比賽使用所有的n個題目,此時方案只有1種。
  
  通過簡單估算,小明發現總方案數幾乎是一個天文數字!
  爲了簡化問題,如今小明只想知道在全部的方案裏面第m小的方案,它的比賽難度是多少呢?
 

 

Input
輸入數據的第一行爲一個整數T(1 <= T <= 20),表示有T組測試數據。
每組測試數據第一行爲兩個整數n, m(0 < n, m <= 10000),表示如今有n個題目,如今要求第m小的方案的比賽難度。接下來第二行有n個數字,分別表示這n個題目的難度值。
 

 

Output
對於每組測試數據,輸出一行"Case #c: ans"(不包含引號),ans 表示要求的第m小的比賽難度,輸入數據保證存在第m小的方案,具體參見樣例。
 

 

Sample Input

2
5 6
1 1 1 1 1
5 25
1 2 3 4 5編程

 

 

Sample Output

Case #1: 2
Case #2: 11ide

 

 解題目報告測試

題目大意:spa

  有N個包含難度值的題目,每次比賽能夠選若干個不一樣題目,則有C(N,1)+C(N,2)+...+C(N,N)種可能的題目組合的方案,每一個方案的題目難度的總和則稱爲比賽難度。讓你輸出第M小的方案的比賽難度。code

思路:blog

  若是隻是考慮去計算因此方案的比賽方案的話,0<N<=10000,方案數有C(N,1)+C(N,2)+...+C(N,N),不可能枚舉因此的方案數再去求第M小的方案的比賽難度。隊列

不過,M的範圍是限制在(0,10000]之間,也就是這題的突破口在在於直接求解第M小的數便可,也就是每次取出最小的那個方案的比賽難度,取M次便可、ip

  假如咱們有N個題目,題目難度分別爲X1,X2,X3...XN(Xi<=XJ,i<j)。string

  咱們能夠很容易知道,比賽方案最小的比賽難度爲X1,

  一樣,也能夠知道,比賽方案第二小的比賽難度爲X2

  若是繼續求解第三小的比賽難度,那第三小的是X1+X2,仍是X3呢,

    若是,第三小的是X3,那麼第四小的是X1+X2,仍是X4呢。

    若是,第三小的是X1+X2,那麼第四小的是X1+X3,仍是X3呢?

  

  對於求最小值或者最大值的問題,咱們能夠用優先隊列來求解,但如何求解也在於你如何構造一個合理的結構體來實現、

  首先,咱們要構造的這個結構體,確定是要來記錄某一個方案的比賽難度的總和、

  而後,咱們能夠肯定的是第一小的方案的比賽難度,可是如何實現記錄每個方案的比賽難度呢?

  咱們先把全部題目的比賽的難度都先排好序,從小到大依次拿題目,便能保證你下一個方案的比賽難度是遞增的。

  咱們保證,第一次拿出來的結構體(方案)是最小的,而後在第一次那結構體(方案)的基礎上,放入比它大的其餘方案(結構體),這樣,每次一樣的操做,即可以實如今第M次拿出第M小的方案的比賽難度。

  咱們要實現每一個方案先後是有關聯的,也就是說咱們須要構建的結構體也是須要可以關聯到先後方案的。

  咱們在結構體裏面,定義一個Sum,用來記錄以前方案的比賽難度的總和。(前關聯)

  而後在定義一個ID,則是表示當前加入的方案的題目難度。(後關聯)

  每個結構體表示的方案的比賽難度則是=Sum+Num[ID];

1 struct Node
2 {           //每個結構體表示一種題目難度總和=Sum+Num[ID];
3     int Sum;//記錄以前題目難度的總和,
4     int ID;//記錄下一個題目的難度
5     friend bool operator <(Node a,Node b){
6         return a.Sum+Num[a.ID]>b.Sum+Num[b.ID];
7     }//把題目難度總和比較小的優先
8 };
須要構建的合理的結構體

  構建完結構體,還有很重要的一點是,如何正確放入下一個方案?

  咱們能夠知道,對於當前方案的話,比賽的難度爲Sum+Num[ID],那麼,比他大的方案有也就只有Sum+Num[ID+1]。(更新下標值)

  並且,你還須要更新下一個方案的比賽難度的總和,也就是(Sum+Num[ID])+Num[ID+1]。(更新方案的比賽難度總和)

  用優先隊列維護最小值,每次取出最小值在進行更新即可以得出第M小的方案的比賽難度、

 

  PS:對放入(Sum+Num[ID])+Num[ID+1]仍是不太理解的話,能夠想一想,雖然Sum+Num[ID+1]確定小於(Sum+Num[ID])+Num[ID+1],

  但你沒法肯定,你的下下一個方案也就是Sum+Num[ID+1]+Num[ID+2]是否會比(Sum+Num[ID])+Num[ID+1]小?

  這樣, 也纔可以把全部方案從小到大都放入優先隊列中,在不懂的就本身去畫畫圖就大概知道爲何了、

  

 1 #include <iostream>
 2 #include <algorithm>
 3 #include <string>
 4 #include <queue>
 5 #include <stdio.h>
 6 #include <string.h>
 7 #include <stdlib.h>
 8 using namespace std;
 9 int Num[10100];//Num[i],記錄第i個題目的難度
10 struct Node
11 {           //每個結構體表示一種題目難度總和=Sum+Num[ID];
12     int Sum;//記錄以前題目難度的總和,
13     int ID;//記錄下一個題目的難度
14     friend bool operator <(Node a,Node b){
15         return a.Sum+Num[a.ID]>b.Sum+Num[b.ID];
16     }//把題目難度總和比較小的優先
17 };
18 int main()
19 {
20     int T,N,M,i,t=1;
21     Node TMD;
22     scanf("%d",&T);
23     while(T--){
24         priority_queue<Node>q;
25         scanf("%d%d",&N,&M);
26         for(i=0;i<N;i++){
27             scanf("%d",&Num[i]);
28         }
29         sort(Num,Num+N);//將題目難度小的排在前面
30         TMD.Sum=0;//初始狀態,題目難度爲0
31         TMD.ID=0;//默認從最小的開始
32         q.push(TMD);
33         printf("Case #%d: ",t++);
34         while(M--){
35             TMD=q.top();q.pop();
36             if(M==0){//輸出第M小的題目難度總和
37                 printf("%d\n",TMD.Sum+Num[TMD.ID]);
38             }
39             if(++TMD.ID<N){
40                 q.push(TMD);//更新的下標值的
41                 TMD.Sum+=Num[TMD.ID-1];
42                 q.push(TMD);//更新下標值以及總和
43             }
44         }
45     }
46     return 0;
47 }
View Code
相關文章
相關標籤/搜索