ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

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

2022-07-16 17:00:14  阅读:157  来源: 互联网

标签:背包 01 int 详解 MAXN 物品 体积 动态


        上一次我们讲了动态规划的定义以及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

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有