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),而其他容量不能得到合法的解。

 

 

 

 

 

 


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