对于普通的01背包问题,如果修改限制条件的大小,让数据范围比较大的话,比如相比较重量而言,价值的范围比较小,我们可以试着修改dp的对象,之前的dp针对不同的重量限制计算最大的价值。这次用dp针对不同的价值计算最小的重量。
定义dp[i+1][j],前i个物品中挑选出价值总和为j时总重量的最小值(不存在时就是一个充分大的数值INF)。由于前0个物品中什么都挑选不了,所以初值为:
dp[0][0]=0;
dp[0][j]=INF;
此外,前i个物品中挑选出价值总和为j时,一定有
前i-1个物品中挑选价值总和为j的部分
前i-1个物品中挑选价值总和为j-v[i]的部分,然后再选中第i个物品。
这两种方法之一,所以就能得到
dp[i+1][j]=min(dp[i][j],dp[i][j-v[i]]+w[i]);
这一递推式。最终的答案就对应于令dp[n][j]<=W的最大j。
则核心代码为:
int dp[MAX_N+1][MAX_N*MAX_V+1];///dp数组
void solve()
{
for(int i=0; i<=MAX_N*MAX_V; i++)
dp[0][i]=INF;
dp[0][0]=0;
for(int i=0; i<n; i++)
for(int j=0; j<=MAX_N*MAX_V; j++)
{
if(j<v[i])
dp[i+1][j]=dp[i][j];
else
dp[i+1][j]=min(dp[i][j],dp[i][j-v[i]]+w[i]);
}
int ans=0;
for(int i=0; i<=MAX_N*MAX_V; i++)
if(dp[n][i]<+W) ans=i;
printf("%d\n",ans);
}