Time Limit: 3000/1000 MS (Java/Others) Memory Limit: 65535/32768 K (Java/Others)
Total Submission(s): 817 Accepted Submission(s): 296
ios
2
5 6
1 1 1 1 1
5 25
1 2 3 4 5編程
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 }