完全背包

 

 完全背包就是一个物品可以无限次使用。

具体可以看01背包,完全背包就是状态计算的集合的划分不一样,状态表示和01背包是基本相似的,这里怎么划分呢,比如每件物品可以拿k次,如果0次的话就相当于不拿第i件,那就是f[i-1][j],大于0件的话就可以表示为f[i-1][j-k*v[i]]+k*w[i],就是先拿走第i件,i-1,再减去他的体积,有k个i,就是j-k*v[i],然后还得加回来,就+k*w[i],就得出了状态转移方程,其实拿0件我们也可以合并在一起,就相当于k=0,所以综上所述:

这是最基本的朴素做法。这个时间复杂度比较大。

#include<iostream>

using namespace std;

const int N = 1010;

int n,m;
int v[N],w[N];
int f[N][N];

int main()
{
    cin >> n >> m;
    for(int i=1;i<=n;i++) cin >> v[i] >> w[i];
    
    for(int i=1;i<=n;i++)
        for(int j=0;j<=m;j++)
            for(int k=0;k*v[i]<=j;k++)
                f[i][j]=max(f[i][j],f[i-1][j-k*v[i]]+k*w[i]);
    cout << f[n][m] << endl;
    return 0;
}

我们可以把它优化成二维的

#include<iostream>

using namespace std;

const int N = 1010;

int n,m;
int v[N],w[N];
int f[N][N];

int main()
{
    cin >> n >> m;
    for(int i=1;i<=n;i++) cin >> v[i] >> w[i];
    
    for(int i=1;i<=n;i++)
        for(int j=0;j<=m;j++)
        {
            f[i][j]=f[i-1][j];
            if(j>=v[i])    f[i][j]=max(f[i][j],f[i][j-v[i]]+w[i]);
        }
    cout << f[n][m] << endl;
    return 0;
}

那其实这样看起来其实和01背包的代码差不多对吧,就有细微的不一样。

然后还能优化,可以将它优化到一维,

#include<iostream>

using namespace std;

const int N = 1010;

int n,m;
int v[N],w[N];
int f[N];

int main()
{
    cin >> n >> m;
    for(int i=1;i<=n;i++) cin >> v[i] >> w[i];
    
    for(int i=1;i<=n;i++)
        for(int j=v[i];j<=m;j++)
        {
            f[j]=max(f[j],f[j-v[i]]+w[i]);
        }
    cout << f[m] << endl;
    return 0;
}

 

 

  

 

posted @ 2020-02-26 10:48  zust-lms  阅读(154)  评论(0编辑  收藏  举报