01揹包&&徹底揹包_順序枚舉和逆序枚舉的問題_一維數組

逆序枚舉和順序枚舉差別主要在一維數組實現的時候出現ios

方程: dp[j]=max(dp[j],dp[j-w[i]]+v[i]);數組

測試樣例:ide

 3 5測試

 3 5        2 6          4 10spa

 

逆序結果: 113d

順序結果: 12code

12這個錯誤的數據是怎麼來的?blog

 

利用check,打印每次枚舉後的結果, 代碼以下繼承

 1 #include <iostream>
 2 #include <cstring>
 3 #include <cstdio>
 4 using namespace std;
 5 const int M=1e5+10;
 6 int w[M],v[M];
 7 int n,m;
 8 int dp[M];
 9 
10 int T;
11 void check(int i,int j) {
12 
13     cout<<"容量爲"<<j<<"的揹包中,"<<"放入第"<<i<<"個物品\n";
14     printf("容量: ");
15     for(int k=1; k<=m; k++) {
16         cout<<k<<" ";
17     }
18     printf("\n價值: ");
19     for(int k=1; k<=m; k++) {
20         cout<<dp[k]<<" ";
21     }
22     puts("\n\n");
23 }
24 /*
25 3 5
26 3 5 2 6 4 10
27 
28 */
29 void f1() {
30     memset(dp,0,sizeof(dp));
31     //dp[j]=max(dp[j],dp[j-w[i]]+v[i]);i(1,n),j>=w[i],
32     //容量初始值j=m
33     //決策時i爲常數, 因此 i 在最外層
34     for(int i=1; i<=n; i++) {
35         /*
36         for(int j=m; j>=w[i]; j--) { //
37             dp[j]=max(dp[j],dp[j-w[i]]+v[i]);
38         }*/
39         for(int j=1; j<=m; j++) {
40             if(j>=w[i])dp[j]=max(dp[j],dp[j-w[i]]+v[i]);
41             check(i,j);
42         }
43     }
44     cout<<dp[m]<<endl;
45 }
46 void f2() {
47     memset(dp,0,sizeof(dp));
48     //dp[j]=max(dp[j],dp[j-w[i]]+v[i]);i(1,n),j>=w[i],
49     //容量初始值j=m
50     //決策時i爲常數, 因此 i 在最外層
51     for(int i=1; i<=n; i++) {
52 
53         for(int j=m; j>=w[i]; j--) { //
54             dp[j]=max(dp[j],dp[j-w[i]]+v[i]);
55             check(i,j);
56         }
57 
58     }
59     cout<<dp[m]<<endl;
60 }
61 /*
62 5 1000
63 144 990
64 487 436
65 210 673
66 567 58
67 1056 897
68 
69 2099
70 */
71 int main() {
72 
73     cin>>n>>m;
74     for(int i=1; i<=n; i++)cin>>w[i]>>v[i];
75     f1();
76     system("pause");
77     f2();
78 
79     return 0;
80 }
View Code

 

 

 

 對於放入第2個物品,容量爲3的枚舉,dp[3]= 6, 6= dp[3-2]+6ci

 對於放入第2個物品,容量爲4的枚舉,dp[4]= 12, 12= dp[4-2]+6 

在第4次枚舉的時候發現問題,

緣由在於dp[4]=dp[j]=max(dp[j],dp[j-w[i]]+v[i]);

dp[4]=dp[2]+6 = 6+6

然鵝,dp[2]已經更新過,經過裝入物品2,

此時dp[2]的值是容量爲2的時候的最大值, 

在這個過程裏, 第2個揹包被使用了兩次, 

重複枚舉就是利用先更新容量小的揹包實現的

而dp[5]則是直接繼承了dp[4]

每次都利用以前的最大值,而且每一個揹包都放進去試一試, 能夠繼承已經更新過的--前驅揹包的--"最大價值", 也就能夠重複無限次, 

這樣枚舉出來的結果是徹底揹包的最大價值

============//=============

而逆序枚舉呢?

 

 

 和順序枚舉不同的地方從放入第2個物品開始,

逆序 dp[5]=dp[5-2]+6=dp[3]+6, 同樣用的是以前更新過的最大值,

可是區別在於, 以前更新過的dp[3], 並無被第2個物品放入過, 也就是說沒有被枚舉更新過, 也就是說不存在重複更新,

同理, dp[4] =dp[4-2]+6=dp[2]+6;

此時dp[2]=0, 尚未被更新過,尚未嘗試放入第2個物品過,

不存在:  容量小的揹包在容量大的揹包被更新以前就更新過

 

結論: 順序枚舉是可取無限次物品的結果, 逆序枚舉是每種物品只取一次的結果

相關文章
相關標籤/搜索