ACM HDU Bone Collector 01背包

来源:互联网 发布:淘宝圣手魔方 编辑:程序博客网 时间:2024/05/19 21:59

Bone Collector

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 45490    Accepted Submission(s): 18925


Problem 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 231).
 

Sample Input
1
5 10
1 2 3 4 5
5 4 3 2 1
 

Sample Output
14
 

这是做的第一道01背包的题目。题目的大意是有n个物品,体积为v的背包。不断的放入物品,当然物品有各自的体积和价值。在不超过总体积v的情况下,问能够达到的最大价值。并且物品是一个一个放入的。最后若有剩余的体积也不会填满。
刚开始是用贪心做的。将价值与体积的比值设定为一个值,即单位价值。然后按照单位价值排序,挨个取物品,考虑到了体积为0的情况,就将单位价值设定为无穷大。但是这样做并不能保证最优解。例如:总体积为5,一共有两个物品。第一个体积4,价值6。第二个体积为2,价值为4。很明显第一个更合适,但是按照单位价值比来做。结果就不是这样的了。所以贪心法不适合这样的01背包。但是适合物品可以只取一部分的01背包,是的最后的背包肯定会被刚好填满。
在这道题中用数组dp来保存运算结果。例如dp[i][j]表示前i个物品放入体积为j的背包中。
判断第i个物品能否放入大小为j的背包中。如果可以,是放?还是不放?
如果放,相当于前i-1个物品放入大小为j-vol[i]的背包中,再加上价值为val[i]的第i个背包。如果不放,相当于前i-1个物品放入大小为j的背包中。即有dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - vol[i]] + val[i]);
如果不可以,相当于前i-1个物品放入大小为j的物品中。即有dp[i][j] = dp[i - 1][j];
重点是可以放的情况!
最后需要注意的是体积可以为0,同时最后结果保存在dp[n][v]中。
附上源代码:
#include<iostream>#include<stdio.h>#include<stdlib.h>#include<string>#include<string.h>#include<math.h>#include<map>#include<vector>#include<algorithm>using namespace std;#define MAX 0x3f3f3f3f#define MIN -0x3f3f3f3f#define N 1005int val[N];int vol[N];int dp[N][N];int main(){int T;int i, j;int n, v;//物品,背包体积scanf("%d", &T);while (T--){scanf("%d%d", &n, &v);for (i = 1; i <= n; i++)scanf("%d", &val[i]);for (i = 1; i <= n; i++)scanf("%d", &vol[i]);memset(dp, 0, sizeof(dp));for (i = 1; i <= n; i++){for (j = 0; j <= v; j++)//体积可以是0{if (vol[i] <= j)//第i个物品的体积可以放到大小为j的背包中dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - vol[i]] + val[i]);//如果不放,前i-1件物品放入大小为v的包中。放的话,前i-1件物品放入v-vol[i]大的背包中elsedp[i][j] = dp[i - 1][j];//放不进去的话,相当于前i-1件物品放入大小为v的背包中}}printf("%d\n", dp[n][v]);}return 0;}


顺便在附上错误的贪心代码,警告自己!
#include<iostream>#include<stdio.h>#include<stdlib.h>#include<string>#include<string.h>#include<math.h>#include<map>#include<vector>#include<algorithm>using namespace std;#define MAX 0x3f3f3f3f#define MIN -0x3f3f3f3fstruct node{int volume;int vaule;double f;}ans[1005];int cmp(const void *a, const void *b){struct node *aa = (node *)a;struct node *bb = (node *)b;return(((aa->f)<(bb->f)) ? 1 : -1);}int main(){int T;int N, V;int i;int val;//价值int vol;//体积scanf("%d", &T);while (T--){scanf("%d%d", &N, &V);for (i = 0; i < N; i++){scanf("%d", &ans[i].vaule);}for (i = 0; i < N; i++){scanf("%d", &ans[i].volume);if (ans[i].volume == 0)ans[i].f = MAX;elseans[i].f = ans[i].vaule*1.0 / ans[i].volume;}qsort(ans, N, sizeof(ans[0]), cmp);val = 0;vol = 0;ans[N].vaule = 0;ans[N].volume = 0;ans[N].f = 0;for (i = 0; i <= N; i++){if (vol <= V){val = val + ans[i].vaule;vol = vol + ans[i].volume;}else if (vol>V){val = val - ans[i - 1].vaule;//vol = vol - ans[i - 1].volume;//val = val + (V - vol)*(int)ans[i - 1].f;break;}}printf("%d\n", val);}return 0;}
等等,这个问题还没完。我发现了什么。二维数组跟新的时候第二重for循环改成v~0结果,居然还能够AC,amazing!虽然不太明白原因,先上图。



1 0
原创粉丝点击