我的编程空间,编程开发者的网络收藏夹
学习永远不晚

C语言动态规划多种背包问题怎么解决

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

C语言动态规划多种背包问题怎么解决

这篇文章主要介绍了C语言动态规划多种背包问题怎么解决的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇C语言动态规划多种背包问题怎么解决文章都会有所收获,下面我们一起来看看吧。

01背包问题

C语言数学问题与简单DP01背包问题详解

先回忆一下这个图

C语言动态规划多种背包问题怎么解决

在这我再将01背包问题代码发一遍,可以用来做对比。

C语言动态规划多种背包问题怎么解决

二维:

#include<bits/stdc++.h>using namespace std;const int MAXN = 1005;int v[MAXN];    // 体积int w[MAXN];    // 价值 int f[MAXN][MAXN];  // f[i][j], j体积下前i个物品的最大价值 int main() {    int n, 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 = 1; j <= m; j++)        {            //  当前背包容量装不进第i个物品,则价值等于前i-1个物品            if(j < v[i])                 f[i][j] = f[i - 1][j];            // 能装,需进行决策是否选择第i个物品            else                    f[i][j] = max(f[i - 1][j], f[i - 1][j - v[i]] + w[i]);        }               cout << f[n][m] << endl;    return 0;}

一维:

#include<bits/stdc++.h>using namespace std;const int MAXN = 1005;int f[MAXN];  // int main() {    int n, m;       cin >> n >> m;    for(int i = 1; i <= n; i++) {        int v, w;        cin >> v >> w;      // 边输入边处理        for(int j = m; j >= v; j--)            f[j] = max(f[j], f[j - v] + w);    }    cout << f[m] << endl;    return 0;}

完全背包问题

C语言动态规划多种背包问题怎么解决

完全背包问题和01背包问题的区别就在于完全背包问题中每件物品都有无限件可用。我们也可以先来试一下暴力写法。

#include<iostream>using namespace std;const int N = 1010;int n, m;int dp[N][N], v[N], w[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 ++ )//因为每一件物品都有无限件可用,我们只需要找出单件价值最高的商品就可以了                dp[i][j] = max(dp[i][j], dp[i - 1][j - k * v[i]] + k * w[i]);    cout << dp[n][m] << endl;}

优化思路:

我们列举一下更新次序的内部关系:

f[i , j ] = max( f[i-1,j] , f[i-1,j-v]+w , f[i-1,j-2v]+2w , f[i-1,j-3v]+3w , &hellip;)

f[i , j-v]= max( f[i-1,j-v] , f[i-1,j-2v] + w , f[i-1,j-3v]+2*w , &hellip;)

由上两式,可得出如下递推关系:

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

有了上面的关系,那么其实k循环可以不要了,核心代码优化成这样:

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]>=0)        f[i][j]=max(f[i][j],f[i][j-v[i]]+w[i]);}

这个代码和01背包的非优化写法很像啊!!!我们对比一下,下面是01背包的核心代码

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]>=0)        f[i][j] = max(f[i][j],f[i-1][j-v[i]]+w[i]);}

两个代码其实只有一句不同(注意下标)

f[i][j] = max(f[i][j],f[i-1][j-v[i]]+w[i]);//01背包

f[i][j] = max(f[i][j],f[i][j-v[i]]+w[i]);//完全背包问题

因为和01背包代码很相像,我们很容易想到进一步优化。核心代码可以改成下面这样

for(int i = 1 ; i<=n ;i++)    for(int j = v[i] ; j<=m ;j++)//注意了,这里的j是从小到大枚举,和01背包不一样    {            f[j] = max(f[j],f[j-v[i]]+w[i]);    }

综上所述,完全背包的最终写法如下:

#include<iostream>using namespace std;const int N = 1010;int f[N];int v[N],w[N];int main(){    int n,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 = v[i] ; j<=m ;j++)    {            f[j] = max(f[j],f[j-v[i]]+w[i]);    }    cout<<f[m]<<endl;}

多重背包问题 I

C语言动态规划多种背包问题怎么解决

我们先来看这多重背包问题和01背包问题是不是很像,将s&times;v,s&times;w是不是就可以看成01背包问题了?

for(ll i=1;i<=n;i++)    {        cin>>a>>b>>c;        for(ll j=1;j<=c;j++)        {            v[cnt]=a;            w[cnt]=b;            cnt++;        }//将多重背包一个一个拆出来    }

然后转换成01背包问题解决。

#include <bits/stdc++.h>using namespace std;typedef long long ll;const ll N=1e5+100;ll v[N],w[N];ll f[N];int main(){    ll n,m;    ll cnt=1;    cin>>n>>m;    ll a,b,c;    for(ll i=1;i<=n;i++)    {        cin>>a>>b>>c;        for(ll j=1;j<=c;j++)        {            v[cnt]=a;            w[cnt]=b;            cnt++;        }//将多重背包一个一个拆出来    }    for(ll i=1;i<=cnt;i++)    {        for(ll j=m;j>=v[i];j--)        {            f[j]=max(f[j],f[j-v[i]]+w[i]);        }    }//01背包    cout<<f[m];    return 0;}

多重背包问题 II

C语言动态规划多种背包问题怎么解决

这道题和1看起来没什么区别,但是数据范围变了,数据范围变了如果不优化就话超时,那怎么优化呢?

我们只需要将转换成01背包问题那一部分优化了就可以了。

int cnt = 0;     // 将物品重新分组后的顺序    for (int i = 1; i <= n; i ++)    {        int a, b, s;    // a 体积, b 价值, s 每种物品的个数        scanf("%d %d %d", &a, &b, &s);        int k = 1;   // 二进制拆分 打包时每组中有 k 个同种物品        while (k <= s)  // 即y总说的: 最后一组的物品个数 < 2^(n+1)   1 2 4 8 16 ... 2^n 2^(n+1)        {            cnt ++;            v[cnt] = a * k;  // 每组的体积            w[cnt] = b * k;  // 每组的价值            s -= k;            k *= 2;  // 注意是 k * 2,每次增长一倍,不是k * k        }        if (s > 0)   // 二进制拆分完之后 剩下的物品个数分为新的一组        {            cnt ++;            v[cnt] = a * s;            w[cnt] = b * s;        }    }

为什么可以这样优化呢

我们知道任何一个数都可以转化成二进制的数,那二进制和十进制的区别在哪呢?

一 、二进制与十进制

  • 普通遍历问题

遍历 n 个物品, 采用二进制计数方法遍历与采用十进制技术方法遍历的时间复杂度是一样的

举例来说, 对于十进制数 8

十进制遍历: 0,1,2,3,4,5,6,7 共 8 次遍历

二进制遍历: 000, 001, 010, 011, 100, 101, 110, 111 共 8 次遍历

  • 多重背包问题

同样的道理, 对于多重背包问题, 采用二进制的遍历方法不能优化时间复杂度

优化的原因在于引入了动态规划

二 、动态规划的时间复杂度估算

动态规划的时间复杂度 &asymp;&asymp; 问题的总个数 &times; 问题要做出的选择数

如, 对于 01 背包问题, 问题的总个数为N&sdot;V (N 为物品个数, V 为背包容量), 问题要做出的选择数为 2(选或不选)

则 01 背包问题的时间复杂度约为 2N&sdot;V

三 、多重背包

如果不采用动态规划的做法, 就像普通的遍历问题那样, 是否采用二进制的计数方法对时间复杂度的优化没有任何关系

但采用二进制的计数方法会影响问题的总个数与问题的选择数的乘积, 即动态规划做法下多重背包的时间复杂度

多重背包的动态规划时间复杂度

十进制遍历方法

问题的总个数为 N&sdot;V, N 为物品的种类数, V 为背包容量

问题的选择数约为 Smax,Smax 为每种物品数量的最大值

十进制下多重背包问题的 DP 时间复杂度为: N&sdot;V&sdot;Smax

二进制遍历方法

十进制下, 一种物品有 si个, 二进制下, 变为 1, 2, &hellip; , lgsi 个物品, 则共有 lgs1+lgs2+&hellip;+lg⁡sn 个物品, 约为 Nlgsmax 个物品

问题的总个数为 N&sdot;V&sdot;lgsmax

问题的选择数为 2

十进制下多重背包问题的 DP 时间复杂度为: 2N&sdot;V&sdot;lgsmax

最后请看代码

#include <bits/stdc++.h>using namespace std;const int N = 11 * 1000 + 10, M = 2010;int v[N], w[N];int f[M];int main(){    int  n, m;    scanf("%d %d", &n, &m);    int cnt = 0;     // 将物品重新分组后的顺序    for (int i = 1; i <= n; i ++)    {        int a, b, s;    // a 体积, b 价值, s 每种物品的个数        scanf("%d %d %d", &a, &b, &s);        int k = 1;   // 二进制拆分 打包时每组中有 k 个同种物品        while (k <= s)  // 即y总说的: 最后一组的物品个数 < 2^(n+1)   1 2 4 8 16 ... 2^n 2^(n+1)        {            cnt ++;            v[cnt] = a * k;  // 每组的体积            w[cnt] = b * k;  // 每组的价值            s -= k;            k *= 2;  // 注意是 k * 2,每次增长一倍,不是k * k        }        if (s > 0)   // 二进制拆分完之后 剩下的物品个数分为新的一组        {            cnt ++;            v[cnt] = a * s;            w[cnt] = b * s;        }    }    n = cnt;  // 所有的组数即为 01背包中的物品个数    // 写01背包模板    for (int i = 1; i <= n; i ++)        for (int j = m; j >= v[i]; j --)            f[j] = max(f[j], f[j - v[i]] + w[i]);    printf("%d", f[m]);    return 0;}

分组背包问题

C语言动态规划多种背包问题怎么解决

  • 状态表示:f[i][j]

集合:从前i组物品中选,且总体积不超过j的所有方案的集合.

属性:最大值

  • 状态计算:

思想-----集合的划分

集合划分依据:根据从第i组物品中选哪个物品进行划分.

f[i][j] = max(f[i][j], f[i - 1][j - v[i][k]] + w[i][k]);

请看代码

#include<bits/stdc++.h>using namespace std;const int N=110;int f[N][N];  //只从前i组物品中选,当前体积小于等于j的最大值int v[N][N],w[N][N],s[N];   //v为体积,w为价值,s代表第i组物品的个数int n,m,k;int main(){    cin>>n>>m;    for(int i=1;i<=n;i++){        cin>>s[i];        for(int j=0;j<s[i];j++){            cin>>v[i][j]>>w[i][j];  //读入        }    }    for(int i=1;i<=n;i++){        for(int j=0;j<=m;j++){            f[i][j]=f[i-1][j];  //不选 不选表示不选第 i 组物品的所有物品,只从前 i−1 组物品里面选            for(int k=0;k<s[i];k++){                if(j>=v[i][k])     f[i][j]=max(f[i][j],f[i-1][j-v[i][k]]+w[i][k]);              }        }    }    cout<<f[n][m]<<endl;}

因为只用到了第i-1列,所以可以仿照01背包的套路逆向枚举体积

#include<bits/stdc++.h>using namespace std;const int N=110;int f[N];int v[N][N],w[N][N],s[N];int n,m,k;int main(){    cin>>n>>m;    for(int i=0;i<n;i++){        cin>>s[i];        for(int j=0;j<s[i];j++){            cin>>v[i][j]>>w[i][j];        }    }    for(int i=0;i<n;i++){        for(int j=m;j>=0;j--){            for(int k=0;k<s[i];k++){    //for(int k=s[i];k>=1;k--)也可以                if(j>=v[i][k])     f[j]=max(f[j],f[j-v[i][k]]+w[i][k]);              }        }    }    cout<<f[m]<<endl;}

关于“C语言动态规划多种背包问题怎么解决”这篇文章的内容就介绍到这里,感谢各位的阅读!相信大家对“C语言动态规划多种背包问题怎么解决”知识都有一定的了解,大家如果还想学习更多知识,欢迎关注编程网行业资讯频道。

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

C语言动态规划多种背包问题怎么解决

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

C语言动态规划多种背包问题怎么解决

这篇文章主要介绍了C语言动态规划多种背包问题怎么解决的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇C语言动态规划多种背包问题怎么解决文章都会有所收获,下面我们一起来看看吧。01背包问题C语言数学问题与简单DP0
2023-06-30

C++动态规划中关于背包问题怎么解决

本篇内容主要讲解“C++动态规划中关于背包问题怎么解决”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“C++动态规划中关于背包问题怎么解决”吧!一、分割等和子集-最后一块石头的重量II背包问题,难
2023-07-05

C++动态规划中关于背包问题讲解

可能有些读者有接触过动态规划,可能也有一些读者以前完全不知道动态规划这个东西,别担心,我这篇文章会为读者做一个入门,好让读者掌握这个重要的知识点
2023-03-15

C++中的动态规划子序列问题怎么解决

今天小编给大家分享一下C++中的动态规划子序列问题怎么解决的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。一、子序列(不连续)
2023-07-05

C语言数学问题与简单DP背包问题怎么解决

本篇内容介绍了“C语言数学问题与简单DP背包问题怎么解决”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!数学顾名思义,数学类的题就是都可以用数
2023-06-30

怎么使用c语言动态规划求解最短路径

在C语言中使用动态规划求解最短路径,可以按照以下步骤进行:1. 定义一个二维数组来表示图中各个节点之间的距离。假设有n个节点,则可以定义一个n×n的二维数组dist[][],其中dist[i][j]表示节点i到节点j的距离。2. 初始化di
2023-08-18

c语言静态变量赋值问题怎么解决

在C语言中,静态变量的赋值是在程序运行前就确定的,一般是在编译时期进行赋值。如果需要在运行时期赋值静态变量,可以使用函数来实现。以下是一种解决方法:#include void setStaticVariable(int value) {
2023-10-27

C语言多线程开发中死锁与读写锁问题怎么解决

今天小编给大家分享一下C语言多线程开发中死锁与读写锁问题怎么解决的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。死锁有时,一个
2023-06-30

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录