Bone Collector
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 33651 Accepted Submission(s): 13843
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 ?
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.
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背包问题。看网上有说贪心和DP其实是都能写的。从定义出发,动态规划是指从当前所存在的所有最优状态来推出下一个最优状态。而贪心是从上一个最优状态得到下一个最优状态。贪心以后再去掌握,这里先整理一下今天掌握的DP算法。
DP算法:
首先我们应该明白我们DP的对象应该是体积从0~V每个体积v的最优状态。从0~n-1每次尝试更新各个体积下的最优状态,即当前骨头是否放入。最终得到所有骨头都考虑过后体积V的最优状态。Dp的思想由记忆化搜索引出,递归实现的方法就不再介绍,主要介绍利用递推公式引出的双层for循环实现。DP实现可以分为一维与二维数组实现。
先整理比较简单的二维数组实现:
设置dp[i][j],而对dp[i][j]的定义不同我们也可以写出不同的双层for循环来实现:
1.若dp[i][j]表示从第i个骨头开始挑选总体积小于j时,总价值的最大值。代码如下:
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <cstring>
#define MAX_N 1010
#define MAX_V 1010
using namespace std;
int T,N,V;
int value[MAX_N];
int v[MAX_N];
int dp[MAX_N][MAX_V];
int main()
{
cin>>T;
while( T-- )
{
cin>>N>>V;
memset(dp,0,sizeof(dp));
for( int i = 0; i < N; i++ )
scanf("%d",&v[i]);
for( int i = 0; i < N; i++ )
scanf("%d",&value[i]);
for( int i = N-1; i >= 0; i-- )
{
for( int j = 0; j <= V; j++ )
{
if( j < value[i] )
dp[i][j]=dp[i+1][j];
else
dp[i][j]=max(dp[i+1][j],dp[i+1][j-value[i]]+v[i]);
}
}
printf("%d\n",dp[0][V]);
}
return 0;
}
2.若dp[i][j]表示从前i个骨头中选出总体积不超过j的骨头时,总价值的最大值。代码如下:
for( int i = 0; i < N; i++ )
{
for( int j = 0; j <= V; j++ )
{
if( j < value[i] )
dp[i+1][j]=dp[i][j];
else
dp[i+1][j]=max(dp[i][j],dp[i][j-value[i]]+v[i]);
}
}
printf("%d\n",dp[N][V]);
3.若dp[i][j]表示从"前i个骨头中选出总体积不超过j时的状态"向"前i+1个骨头中选取总体积不超过j"和"前i+1个骨头中选取总体积不超过j+v[i]"时的状态的转移。代码如下:
一维数组:
for( int i = 0; i < N; i++ )
{
for( int j = 0; j <= V; j++ )
{
dp[i+1][j]=max(dp[i+1][j],dp[i][j]);
if( j+value[i] <= V )
dp[i+1][j+value[i]]=max(dp[i+1][j+value[i]],dp[i][j]+v[i]);
}
}
printf("%d\n",dp[N][V]);
一维数组的解法是在二维数组的基础上的优化,考虑对于每块骨头i都是在i-1的基础上进行判断,而此时i-1对应各个体积已经是最优解,不需要保存,所以我们可以覆盖上去,仅利用一维数组去求解。但是要注意因为涉及到数组的覆盖,所以对于每个骨头i我们都必须从V到value[i]倒序遍历,因为递推方程为dp[j] = max( dp[j], dp[ j-v[i] ]+value[i] ),对于同一个i倒序时dp[j]改变之后便不会再被调用,但是正序的话dp[j]可能会在之后的计算中再次被调用,也就是说骨头会被多次放入。倒序就是为了防止多次放入。代码如下:
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <cstring>
#define MAX_N 1010
#define MAX_V 1010
using namespace std;
int T,N,V;
int value[MAX_N];//
int v[MAX_N];//
int dp[MAX_V];//一位数组存储对应体积v最优解
int main()
{
cin>>T;
while( T-- )
{
cin>>N>>V;
memset(dp,0,sizeof(dp));
for( int i = 0; i < N; i++ )
scanf("%d",&v[i]);
for( int i = 0; i < N; i++ )
scanf("%d",&value[i]);
for( int i = 0; i < N; i++ )
{
//必须要求倒序
for( int j = V; j >= v[i]; j-- )
{
dp[j] = max( dp[j], dp[j-v[i]]+value[i] );
}
}
printf("%d\n",dp[V]);
}
return 0;
}