1. 程式人生 > >背包dp專題訓練

背包dp專題訓練

memset 哪些 eof 程序 sin 一道 -- 字符串 筆記本

新年趣事之打牌

描述

過年的時候,大人們最喜歡的活動,就是打牌了。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專題訓練