与01不同的点只有一个,就是允许物品多次放入
首先分析这个问题得到状态转移方程 dp[i][j]=max(dp[i-1][j],dp[i-1][j-k*w[i]]+v[i]*k);
这是最朴素的方法
实现代码:
for(i=1;i<=n;i++)
{
for(j=1;j<=V;j++)
{
for(k=0;k <= j/w[i-1];k++)
{
dp[i][j] = max_2(dp[i][j], dp[i-1][ j-k*w[i-1] ] + k*p[i-1]);
}
}
}
对于取多个物品的情况 可以写出它的状态转移方程:
dp[i][j]=dp[i][j-w[i]]+v[i] 可以用递归实现
又考虑到01背包时从后向前是为了避免覆盖前一个dp[i-1]的值 那么如果我从前向后就可以得到dp[i][j]=dp[i][k]+v[i] 这种情况
所以完全背包滚掉一维是这种样子:
for(i=1;i<=n;i++)
{
for(j=1;j<=V;j++)
{
for(k=0;k <= j/w[i-1];k++)
{
dp[i][j] = max_2(dp[i][j], dp[i-1][ j-k*w[i-1] ] + k*p[i-1]);
}
}
}
ac代码:
#include<bits/stdc++.h>
using namespace std;
const int MAX=500005;
const int INF=0x3f3f3f3f;
int dp[MAX];
int main (){
int t;
cin>>t;
while(t--){
int n,m;
cin>>n>>m;
m=m-n;
cin>>n;
int coin_w[505],coin_v[505];
for(int i=1;i<=n;i++)
cin>>coin_v[i]>>coin_w[i];
memset(dp,INF,sizeof(dp));
dp[0]=0;
for(int i=1;i<=n;i++)
for(int j=coin_w[i];j<=m;j++)
dp[j]=min(dp[j],dp[j-coin_w[i]]+coin_v[i]);
if(dp[m]==INF)cout<<"This is impossible."<<endl;
else cout<<"The minimum amount of money in the piggy-bank is "<<dp[m]<<"."<<endl;
}
}

京公网安备 11010502036488号