与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;
    }
}