sdnu采药2(完全背包问题)

第一种思路:将能放进背包的第i种物品看做一件物品,转化为0-1背包问题: 

#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int NN=1000;
const int TT=1000;
int v[NN+1];
int t[NN+1];
int c[NN+1][TT+1];
int main()
{
    int T,N,i,j;
    cin>>T>>N;
    for(i=1; i<=N; i++)
        cin>>t[i]>>v[i];
    i=0;
    memset(c,0,sizeof(c));
    for(i=1; i<=N; i++)
        for(int j=1; j<=T; j++)
        for(int j=1; j<=T; j++)
        {
            if(t[i]<=j)
            {
                int k=j/t[i];
                c[i][j]=max(c[i-1][j-k*t[i]]+k*v[i],c[i-1][j]);
            }
            else
                c[i][j]=c[i-1][j];
        }
    cout<<c[N][T]<<endl;
    return 0;
}

优化的方案是从状态本身入手:在0-1背包问题中,状态转移方程是dp[i][j]=max(dp[i-1][j],dp[i-1][j-m[i]]+w[i])

其中dp[i-1][j-m[i]]+w[i] 的含义是考虑放入第i种物品1件,dp[i][j]含义是将前i件物品放进容量为j的背包时的背包价值的最大值

那么dp[i-1][j-m[i]]的含义为:将前i-1件物品放进容量为j-m[i](此时因为放进了一件物品i,所以背包剩余容量是j-m[i])

下面为了解决完全背包问题,我们换一种思考的方式:

将dp[i][j]的含义改变成:放入前i种物品若干件进入容量为j的背包时背包的最大价值,我们再去考虑状态转移方程:

dp[i][j]=max(dp[i-1][j],dp[i][j-m[i]]+w[i])其中括号里前一项表示不放第i种物品,这是好理解的,后一项表示的含义是至少放进1件第i种物品,直接含义是放入前i种物品若干件进入容量为j-m[i]的背包时背包的最大价值(可能放进第i种物品前已经放进了若干件第i种物品)

但是至少会放进一件第i种物品

下面是利用滚动数组优化的代码:

#include<iostream>
#include<cstring>
using namespace std;
const int maxn=1005;
int M,n;
int w[maxn];
int m[maxn];
int dp[maxn];
int main()
{
    memset(dp,0,sizeof(dp));
    cin>>M>>n;
    for(int i=1; i<=n; ++i)
        cin>>m[i]>>w[i];
    for(int i=1; i<=n; ++i)
        for(int j=m[i]; j<=M; ++j)
        {
            dp[j]=max(dp[j],dp[j-m[i]]+w[i]);
        }
    cout<<dp[M]<<endl;
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_41658955/article/details/81488141