背包dp專題訓練
新年趣事之打牌
描述
過年的時候,大人們最喜歡的活動,就是打牌了。xiaomengxian不會打牌,只好坐在一邊看著。
這天,正當一群人打牌打得起勁的時候,突然有人喊道:“這副牌少了幾張!”眾人一數,果然是少了。於是這副牌的主人得意地說:“這是一幅特制的牌,我知道整副牌每一張的重量。只要我們稱一下剩下的牌的總重量,就能知道少了哪些牌了。”大家都覺得這個辦法不錯,於是稱出剩下的牌的總重量,開始計算少了哪些牌。由於數據量比較大,過了不久,大家都算得頭暈了。
這時,xiaomengxian大聲說:“你們看我的吧!”於是他拿出筆記本電腦,編出了一個程序,很快就把缺少的牌找了出來。
如果是你遇到了這樣的情況呢?你能辦到同樣的事情嗎?
格式
輸入格式
第一行一個整數TotalW,表示剩下的牌的總重量。
第二行一個整數N(1<N<=100),表示這副牌有多少張。
接下來N行,每行一個整數Wi(1<=Wi<=1000),表示每一張牌的重量。
輸出格式
如果無解,則輸出“0”;如果有多解,則輸出“-1”;否則,按照升序輸出丟失的牌的編號,相鄰兩個數之間用一個空格隔開。
樣例1
樣例輸入1
270
4
100
110
170
200
Copy
樣例輸出1
2 4
Copy
限制
各個測試點1s
提示
Sample input #2
270
4
100
110
160
170
Sample output #2
-1
Sample input #3
270
4
100
120
160
180
Sample output #3
0
題解
01背包判斷方案數嘛,需要放個vis記錄一下答案的編號
1 #include<cstdio> 2 #include<algorithm> 3 #include<cstring> 4 using namespace std; 5 int V,n,w[105],f[100005],vis[100005],sum,cnt,ans[105];6 int main() 7 { 8 scanf("%d%d",&V,&n); 9 for(int i=1 ; i<=n ; ++i ) 10 { 11 scanf("%d",&w[i]); 12 sum+=w[i]; 13 } 14 V=sum-V; 15 f[0]=1; 16 for(int i=1 ; i<=n ; ++i ) 17 for(int j=V ; j>=w[i] ; --j) 18 { 19 20 if(f[j-w[i]]) 21 { 22 if(!f[j])vis[j]=i; 23 f[j]+=f[j-w[i]]; 24 } 25 } 26 if(!f[V])printf("0"); 27 else if(f[V]>1)printf("-1"); 28 else if(f[V]==1) 29 { 30 for(int i=V ; i>0 ; i-=w[vis[i]])ans[++cnt]=vis[i]; 31 sort(ans+1,ans+1+cnt); 32 for(int i=1 ; i<=cnt ; ++i )printf("%d ",ans[i]); 33 } 34 return 0; 35 }
搭建雙塔
描述
2001年9月11日,一場突發的災難將紐約世界貿易中心大廈夷為平地,Mr. F曾親眼目睹了這次災難。為了紀念“9?11”事件,Mr. F決定自己用水晶來搭建一座雙塔。
Mr. F有N塊水晶,每塊水晶有一個高度,他想用這N塊水晶搭建兩座有同樣高度的塔,使他們成為一座雙塔,Mr. F可以從這N塊水晶中任取M(1≤M≤N)塊來搭建。但是他不知道能否使兩座塔有同樣的高度,也不知道如果能搭建成一座雙塔,這座雙塔的最大高度是多少。所以他來請你幫忙。
給定水晶的數量N(1≤N≤100)和每塊水晶的高度Hi(N塊水晶高度的總和不超過2000),你的任務是判斷Mr. F能否用這些水晶搭建成一座雙塔(兩座塔有同樣的高度),如果能,則輸出所能搭建的雙塔的最大高度,否則輸出“Impossible”。
格式
輸入格式
輸入的第一行為一個數N,表示水晶的數量。第二行為N個數,第i個數表示第i個水晶的高度。
輸出格式
輸出僅包含一行,如果能搭成一座雙塔,則輸出雙塔的最大高度,否則輸出一個字符串“Impossible”。
樣例1
樣例輸入1
5
1 3 4 5 2
樣例輸出1
7
題解
比較好的一道dp,設f[i][j]表示前i個水晶搭的兩座塔相差高度為j時較低塔的高度
四種情況可以轉移
該水晶搭給矮塔後仍然是矮塔 搭給高塔 搭給矮塔後變成高塔 不選該水晶
然後轉移就行了
1 #include<iostream> 2 #include<cstdio> 3 #include<cstdlib> 4 #include<algorithm> 5 #include<cstring> 6 using namespace std; 7 int N; 8 int a[300],sum[300]; 9 int f[300][2500]; 10 int main(){ 11 memset(f,-0x7f,sizeof(f)); 12 cin>>N; 13 for(int i=1;i<=N;i++)cin>>a[i]; 14 sort(a+1,a+N+1); 15 for(int i=1;i<=N;i++) sum[i]=sum[i-1]+a[i]; 16 f[1][0]=0;f[1][a[1]]=0; 17 for(int i=2;i<=N;i++){ 18 for(int j=0;j<=sum[i];j++){ 19 int h1=j-a[i]; 20 if(h1>=0&&h1<=sum[i-1]) 21 f[i][j]=max(f[i][j],f[i-1][h1]); 22 int h2=j+a[i]; 23 if(h2<=sum[i-1]) 24 f[i][j]=max(f[i][j],f[i-1][h2]+a[i]); 25 int h3=a[i]-j; 26 if(h3>=0&&h3<=sum[i-1]) 27 f[i][j]=max(f[i][j],f[i-1][h3]+h3); 28 int h4=j; 29 if(h4<=sum[i-1]) 30 f[i][j]=max(f[i][j],f[i-1][j]); 31 } 32 } 33 if(f[N][0]<=0){ 34 cout<<"Impossible"; 35 return 0; 36 } 37 cout<<f[N][0]; 38 return 0; 39 }
背包dp專題訓練