HDU 2602 Bone Collector 之01揹包

Description

Many years ago , in Teddy’s hometown there was a man who was called “Bone Collector”. This man like to collect varies of bones , such as dog’s , cow’s , also he went to the grave … 
The bone collector had a big bag with a volume of V ,and along his trip of collecting there are a lot of bones , obviously , different bone has different value and different volume, now given the each bone’s value along his trip , can you calculate out the maximum of the total value the bone collector can get ? 

 

Input

The first line contain a integer T , the number of cases. 
Followed by T cases , each case three lines , the first line contain two integer N , V, (N <= 1000 , V <= 1000 )representing the number of bones and the volume of his bag. And the second line contain N integers representing the value of each bone. The third line contain N integers representing the volume of each bone.
 

Output

One integer per line representing the maximum of the total value (this number will be less than 2 31).
 

Sample Input

1 5 10 1 2 3 4 5 5 4 3 2 1
 

Sample Output

14
 
 分析:這是最基礎的01揹包,其原理我就不說了,百度上面都有,可以看看揹包9講。
其實,只要搞清楚邊界問題就好。
代碼如下:
 

#include <iostream> #include <cstdio> #include <cstring> #define max(x,y) x>y?x:y; using namespace std; int a[1050];//價值 int b[1050];//空間 int c[1050][1050]; long long knapsack(int n,int v) { int i,j; for (i = 0; i < n; i++) { for(j = 0; j <= v; j++) { if (j >= b[i+1]) { c[i+1][j] = max(c[i][j],c[i][j-b[i+1]]+a[i+1]); } else { c[i+1][j] = c[i][j]; } } } return c[n][v]; } int main() { int t,n,v,i; scanf("%d",&t); while (t--) { scanf("%d %d",&n,&v); for (i = 1; i <= n; i++) { scanf("%d",&a[i]);//value } for (i = 1; i <= n; i++) { scanf("%d",&b[i]); } memset(c,0,sizeof(c)); cout << knapsack(n,v) << endl; } return 0;

}

 

這是最簡單的一種解法,它的時間,空間複雜度都是O(V*N).

 

下面還有一種對空間的優化,將二維數組變成一維數組dp[v].

代碼如下:

#include <iostream> #include <cstdio> #define max(x,y) x>y?x:y; #include <cstring> using namespace std; int val[1050]; int w[1050]; int dp[1050]; int main () { int t,n,v,i,j; cin >> t; while (t--) { cin >> n >> v; for (i = 0; i < n; i++) { scanf("%d",&val[i]); } for(i = 0; i < n; i++) { scanf("%d",&w[i]); } memset(dp,0,sizeof(dp)); for (i = 0; i < n; i++) { for (j = v; j >= w[i]; j--) { dp[j] = max(dp[j],dp[j-w[i]]+val[i]); } } cout << dp[v] << endl; } }

1.這裏值得注意的是對v我們是逆序的.爲什麼呢?

我們知道01揹包的基本狀態轉移方程:dp[i][j] = max{dp[i-1][j],dp[i-1][j-w[i]]+val[i]};

知道dp[i][j]是由dp[i-1][j-w[i]]+val[i]}更新的而不是dp[i][j-w[i]]+val[i]}。即在優化中,dp[j]由dp[j-w[]i]決定。在進行i-1次循環後dp[j-w[i]]已經確定,是不能更改了的,又我們知道j > j-w[i],所以在第i次循環dp[j-w[i]]會覆蓋i-1次循環得到的dp[j-w[i]],也就是說,dp[i][j]由dp[i][j-w[i]]更新了,這顯然不是我們要的。所以,只有逆序才能達到這個目的。

2.dp[0]——dp[v]我們初始化爲0.

順便說一句,我們的題目是沒有要求揹包一定裝滿。假如要求揹包一定裝滿,那麼我們這樣初始化:dp[0] = 0,dp[1] - dp[v]=無窮大。初始化的含義就是在揹包沒有裝任何東西的情況下所賦的值。顯然dp[0]=0(v = 0),而其他容量不能得到合法的解。

 

 

 

 

 

 


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章