其他分享
首页 > 其他分享> > 动态规划背包详解——完全背包

动态规划背包详解——完全背包

作者:互联网

        上一次我们讲了动态规划的定义以及01背包的算法和代码实现,没读过的请出门左转:https://www.cnblogs.com/YZYc/p/01Pack-Class-YPPAH.html

        今天我们继续上一次的内容,讲一讲另外一种背包——完全背包。完全背包的定义其实和01背包十分相似,都是有n个物品,一个体积为m的背包,每个物品都有自己的体积和价值,但是它和01背包不同的是,完全背包每一个物品都可以放无限次,而01背包每个物品只能使用一次。完全背包的建表和查表也和01背包没有太大差异,不过填表的部分还是和01背包不太一样,让我们详细的来看一下完全背包填表的过程。

        1.1:版本1 暴力解法O(n3)    注:这种方法在毒瘤数据下会TLE,主要理解思路即可

                (1)状态f[i][j](同【01背包】):前i个物品,背包容量为j下的最优解(最大价值)。

                (2)每一轮循环i都可以看作是对第i件物品的决策——选择多少个第i件物品。

                (3)稍微不同的是完全背包允许多次选择一个物品,所以计算状态转移方程时需要枚举选择第i个物品

                代码:

#include<bits/stdc++.h>

using namespace std;

const int MAXN = 10000;
int v[MAXN];    // 体积 
int w[MAXN];    // 价值 
int f[MAXN][MAXN];  // f[i][j], j体积下前i个物品的最大价值 

int main() 
{
    int n;
    int m;  // 背包体积 
    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++) 
        {
            int amount = j / v[i];  // j体积时物品最多能选的次数    
            for(int k = 0; k <= amount; k++) // 枚举选择第i个物品的个数
                f[i][j] = max(f[i][j], f[i - 1][j - k * v[i]] + k * w[i]);   // 状态转移方程
        }

    cout << f[n][m] << endl;
    return 0;
}

        1.2:版本2 优化时间O(n2)

        实际上,我们在计算状态转移方程时不必多一个循环去单独枚举选择第i个物品个数。

        状态转移方程如下:

        推导过程如下:

                我们计算的是前i个物品背包体积为j的最优解f[i][j],而前i-1个物品的最优解f[i-1][j]在上一轮循环中都已计算完毕,现在我们只需判断选择几个第i种物品得到的价值最大。我们改变一下变量,将j变成j-v,则有:

        由以上两个式子就可以得到一个新的状态转移方程:

        f[i][j]=max(f[i-1][j],f[i][j-v])

        我们枚举体积j是从小到大的,那么我们在计算f[i][j]时,f[i][较大体积]总是由f[i][较小体积]更新而来。

        最终代码如下:

#include<bits/stdc++.h>

using namespace std;

const int MAXN = 10000;
int v[MAXN];    // 体积 
int w[MAXN];    // 价值 
int f[MAXN][MAXN];  // f[i][j], j体积下前i个物品的最大价值 

int main() 
{
    int n;
    int m;  // 背包体积 
    cin >> n >> m;
    for(int i = 1; i <= n; i++) 
        cin >> v[i] >> w[i];

    f[0][0] = 0;
    for(int i = 1; i <= n; i++)
        for(int j = 0; j <= m; j++) 
        {
            f[i][j] = f[i - 1][j];  // 不选第i个物品
            if(j >= v[i])           // 可以选择第i个物品,状态方程见上面推导    
                f[i][j] = max(f[i][j], f[i][j - v[i]] + w[i]);
        }

    cout << f[n][m] << endl;
    return 0;
}

        (代码来自:https://www.acwing.com/solution/content/1375/)

 

标签:背包,01,int,详解,MAXN,物品,体积,动态
来源: https://www.cnblogs.com/YZYc/p/FullPack-Class-YPPAH.html