HDU 2602 Bone Collector
大致意思:n个骨头,不同骨头价值和重量不同,知道背包的容量s,求最大价值。
--------------------------------------------------------------------------------------------------------------------------------------------------
动态规划先找出子问题,我们可以这样考虑:在物品比较少,背包容量比较小时怎么解决?用一个数组dp[i][j]表示,在只有i个物品,容量为j的情况下背包问题的最优解,那么当物品种类变大为i+1时,最优解是什么?第i+1个物品可以选择放进背包或者不放进背包,假设放进背包(前提是放得下),那么dp[i+1][j]=dp[i][j-weight[i+1]+value[i+1];
如果不放进背包,那么dp[i+1][j]=dp[i][j]。放不下就是dp[i+1][j]=dp[i][j];
这就得出了状态转移方程:
dp[i+1][j]=max(dp[i][j],dp[i][j-weight[i+1]+value[i+1])
/**01背包**/
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
const int maxn=1010;
int w[maxn];//重量
int v[maxn];//价值
int dp[maxn][maxn];
int n,s;
void slove()
{
for(int i = 1; i <= n; i++)
{
for(int j = 0; j <= s; j++)
{
if(j < w[i])///背包容量比第i个物品的重量小
dp[i][j] = dp[i-1][j];
else
dp[i][j] = max(dp[i-1][j], dp[i-1][j - w[i]] + v[i]);
cout << dp[i][j] << ' ';
}
cout << endl;
}
}
int main()
{
int T;
cin>>T;
while(T--)
{
memset(dp,0,sizeof(dp));
cin>>n>>s;
for(int i=1; i<=n; i++)
cin>>v[i];//价值
for(int i=1; i<=n; i++)
cin>>w[i];//重量
slove();
cout << dp[n][s] << endl;
}
return 0;
}
-------------------------------------------------------------------------------------------------------------------------------------------------------------------
上面计算 dp[i][j]可以看出,在计算 dp[i][j]时只使用了 dp[i-1][0……j],没有使用其他子问题,因此在存储子问题的解时,只存储 dp[i-1]子问题的解即可。这样可以用两个一维数组解决,一个存储子问题,一个存储正在解决的子问题。再进一步思考,计算dp[i][j]时只使用了 dp[i-1][0……j],没有使用dp[i-1][j+1]这样的话,我们先计算j的循环时,让j=M……1,只使用一个一维数组即可。这就得出了状态转移方程:
dp[j]=max(dp[j],dp[j-weight[i]+value[i]) ;
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
int dp[1010],weight[1010],value[1010];//全局变量,自动清0;
int main()
{
int t,n,m,i,j;
cin>>t;
while(t--)
{
memset(dp,0,sizeof(dp));//记得清0;
cin>>n>>m;
for(i=1;i<=n;i++)
cin>>value[i];
for(i=1;i<=n;i++)
cin>>weight[i];
for(i=1;i<=n;i++)
{
for(j=m;j>=weight[i];j--)
{
dp[j]=max(dp[j],dp[j-weight[i]]+value[i]);
}
}
cout<<dp[m]<<endl;
}
return 0;
}