1. 程式人生 > >背包的第k優解[動態規劃]

背包的第k優解[動態規劃]

open tail height val 技術 colspan esp output 理解

From easthong
背包的第k優解
描述 Description
DD 和好朋友們要去爬山啦!他們一共有 K 個人,每個人都會背一個包。這些包的容量是相同的,都是 V。可以裝進背包裏的一共有 N 種物品,每種物品都有給定的體積和價值。

在 DD 看來,合理的背包安排方案是這樣的:

1. 每個人背包裏裝的物品的總體積恰等於包的容量。
2. 每個包裏的每種物品最多只有一件,但兩個不同的包中可以存在相同的物品。
3. 任意兩個人,他們包裏的物品清單不能完全相同。

在滿足以上要求的前提下,所有包裏的所有物品的總價值最大是多少呢?
輸入格式 Input Format
第一行有三個整數:K、V、N。

第二行開始的 N 行,每行有兩個整數,分別代表這件物品的體積和價值。
輸出格式 Output Format
只需輸出一個整數,即在滿足以上要求的前提下所有物品的總價值的最大值。
樣例輸入 Sample Input
樣例輸出 Sample Output
時間限制 Time Limitation
1s
註釋 Hint
數據範圍

總人數 K<=50。

每個背包的容量 V<=5000。

物品種類數 N<=200。

其它正整數都不超過 5000。

輸入數據保證存在滿足要求的方案。
來源 Source
dd 2007 dp 模擬賽
慢慢啃 f[j][u]表示空間為j時的第u優解;
性質:加了一個u循環操作的01背包,i表示加入第i個物品則循環順序從外到裏為i->j->u(就是把原本f[j]=max(f[j-w[i]]+v[i],f[j])的位置變成u的循環操作而已);
初始化: f[j][u]=負無窮(u循環操作前要判定f[j-w[i]][1]>=0),f[0][1]=0; u的循環操作: 1.已知f[j]=max(f[j-w[i]]+v[i],f[j]),即f[j]有兩種取值方案; 用兩個數組st1[u]和st2[u]分別儲存f[j-w[i]][u]+v[i]和f[j][u]; 2.因為f[j][u]一定優於f[j][u+1],所以st1[u]一定優於st1[u+1],st2[u]同理,所以只需要比較st1和st2中的元素就可以得到當前可以取到的最優值; 所以f[i][u]等於st1[tail1]和st2[tail2]中較大的; 3.因為不能有一樣的方案,所以st1[tail1],st2[tail2]中較大的數被f[i][u]取值後,對應的tail++(tail在u循環開始前定義為0或者1); 隨著j的增大,方案數是樹狀增多的,但是前u個最優方案一定是在這棵樹的某一個分支上,這個分支的父節點一定是某一個階段的最優方案,就像分封制一樣,離最後的最優方案血緣關系越遠優秀程度越差,嗯我是這麽理解的..... 因為動態規劃每一個階段的方案只和前一個階段有關,所以可以在輸入數據後直接j循環,不需要v[i]w[i]之類存儲每一個狀態的數組... 技術分享
 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #include<cmath>
 6 using namespace std;
 7 int k,v,n;
 8 long long f[5010][51]={};
 9 long long st1[5010]={};
10 long long st2[5010]={};
11 int main(){
12     cin>>k>>v>>n;
13     for(int i=0;i<v;i++){
14         for(int j=0;j<=k;j++){
15             f[i][j]=-99999999;
16         }
17     }
18     f[0][1]=0;
19     for(int i=1;i<=n;i++){
20         int a,b;
21         cin>>a>>b;
22         for(int j=v;j>=a;j--){
23             if(f[j-a][1]>=0){
24                 int p1=1,p2=1;
25                 for(int u=1;u<=k;u++){
26                     st1[u]=f[j-a][u]+b;
27                     st2[u]=f[j][u];
28                     if(st2[p2]>=st1[p1]) f[j][u]=st2[p2++];
29                     else f[j][u]=st1[p1++];
30                 }
31             }
32         }
33     }
34     long long ans=0;
35     for(int i=1;i<=k;i++){
36         ans+=f[v][i];
37     }
38     cout<<ans<<endl;
39     return 0;
40 }
View Code

背包的第k優解[動態規劃]