iis服务器助手广告广告
返回顶部
首页 > 资讯 > 后端开发 > 其他教程 >C语言动态规划多种背包问题怎么解决
  • 783
分享到

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

2023-06-30 00:06:14 783人浏览 安东尼
摘要

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

这篇文章主要介绍了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语言动态规划多种背包问题怎么解决”知识都有一定的了解,大家如果还想学习更多知识,欢迎关注编程网其他教程频道。

--结束END--

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

本文链接: https://www.lsjlt.com/news/326903.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

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

下载Word文档
猜你喜欢
  • C语言动态规划多种背包问题怎么解决
    这篇文章主要介绍了C语言动态规划多种背包问题怎么解决的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇C语言动态规划多种背包问题怎么解决文章都会有所收获,下面我们一起来看看吧。01背包问题C语言数学问题与简单DP0...
    99+
    2023-06-30
  • C语言动态规划多种背包问题分析讲解
    目录写在前面01背包问题完全背包问题多重背包问题 I多重背包问题 II为什么可以这样优化呢一 、二进制与十进制二 、动态规划的时间复杂度估算三 、多重背包分组背包问题写在前面 之前讲...
    99+
    2024-04-02
  • C语言动态规划之背包问题详解
    01背包问题        给定n种物品,和一个容量为C的背包,物品i的重量是w[i],其价值为v[i]。问如何选择装入背包的物品,使得装入背...
    99+
    2024-04-02
  • C++动态规划中关于背包问题怎么解决
    本篇内容主要讲解“C++动态规划中关于背包问题怎么解决”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“C++动态规划中关于背包问题怎么解决”吧!一、分割等和子集-最后一块石头的重量II背包问题,难...
    99+
    2023-07-05
  • C++动态规划中关于背包问题讲解
    目录一、分割等和子集-最后一块石头的重量II二、目标和三、一和零四、零钱兑换II五、排列与组合组合总数IV(排列问题)零钱兑换(组合问题) 一、分割等和子集-最后一块石头的重量II ...
    99+
    2023-03-15
    C++动态规划背包问题 C++动态规划 C++背包问题
  • Java实现动态规划背包问题
    目录前言一、原理1.1 最优子结构性质1.2 递归关系二、算法描述2.1 算法描述2.2 图解2.3 构造最优解三、 0 − 1 0-1 0−1 背包问题相关...
    99+
    2024-04-02
  • Python算法题解:动态规划解0-1背包问题
    概述背包问题(Knapsack problem)是一种组合优化的NP完全问题。问题可以描述为:给定一组物品,每种物品都有自己的重量和价格,在限定的总重量内,我们如何选择,才能使得物品的总价格最高。问题的名称来源于如何选择最合适的物品放置于给...
    99+
    2023-06-02
  • Java使用动态规划算法思想解决背包问题
    目录动态规划算法动态规划算法的思想最优性原理动态规划算法的三大特点动态规划算法中的0/1背包问题动态规划算法的优点小结动态规划算法 动态规划算法的思想 动态规划算法处理的对象是多阶段...
    99+
    2024-04-02
  • java背包问题动态规划算法分析
    背包问题 【题目描述】 一个旅行者有一个最多能装 MM 公斤的背包,现在有 nn 件物品,它们的重量分别是W1,W2,…,WnW1,W2,…,Wn,它们的价值分别为C1,C2,…,C...
    99+
    2024-04-02
  • 动态规划之什么是多重背包
    本篇内容主要讲解“动态规划之什么是多重背包”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“动态规划之什么是多重背包”吧!多重背包有N种物品和一个容量为V 的背包。...
    99+
    2024-04-02
  • 【动态规划】背包问题(详细总结,很全)
    【动态规划】 一、 背包问题1. 背包问题总结1)动规四部曲:2) 递推公式总结:3) 遍历顺序总结: 2. 01背包1) 二维dp数组代码实现 2) 一维dp数组代码实现 ...
    99+
    2023-09-09
    动态规划 算法 python leetcode
  • python 动态规划问题解析(背包问题和最长公共子串)
    目录背包问题最长公共子串背包问题 现在要往一个可以装4个单位重量的背包里怎么装价值最高:A重量1个单位,价值15;B重量3个单位,价值20;C重量4个重量,价值30 使用动态规划填充...
    99+
    2024-04-02
  • C语言动态内存规划详解
    目录动态内存规划动态内存函数的介绍总结动态内存规划 用C语言写程序时,因为语言的一些特性使用数组的时候只能用常量来申明数组,就导致数组的内存被卡得很死,不能根据我们的实际需求灵活的使...
    99+
    2024-04-02
  • C++中的动态规划子序列问题怎么解决
    今天小编给大家分享一下C++中的动态规划子序列问题怎么解决的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。一、子序列(不连续)...
    99+
    2023-07-05
  • C语言数学问题与简单DP背包问题怎么解决
    本篇内容介绍了“C语言数学问题与简单DP背包问题怎么解决”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!数学顾名思义,数学类的题就是都可以用数...
    99+
    2023-06-30
  • c语言动态规划算法是什么
    C语言动态规划算法是一种用于解决优化问题的算法。它通过将问题划分为子问题,并保存子问题的解来避免重复计算,从而提高算法的效率。动态规...
    99+
    2023-08-18
    c语言
  • 怎么使用c语言动态规划求解最短路径
    在C语言中使用动态规划求解最短路径,可以按照以下步骤进行:1. 定义一个二维数组来表示图中各个节点之间的距离。假设有n个节点,则可以...
    99+
    2023-08-18
    c语言
  • C语言 深入理解动态规划之计数类DP
    目录写在前面石子合并写在前面 之前讲过背包问题,线性DP,区间DP,不知道大家忘了吗,这次是计数类DP 石子合并 老规矩,先画图。 思路:把1,2,3, … n分别...
    99+
    2024-04-02
  • C语言数学问题与简单DP01背包问题详解
    目录数学买不到的数目蚂蚁感冒饮料换购简单DP01背包问题二维一维数学 顾名思义,数学类的题就是都可以用数学知识求解。 买不到的数目 这是第四届蓝桥杯省赛C++A组,第四届蓝桥杯省赛J...
    99+
    2024-04-02
  • C语言动态规划点杀dp算法LeetCode炒股习题案例解析
    目录概念性质典型特征实战论证算法实现优化概念 说到动态规划,什么是动态规划? 动态规划(英语:Dynamic programming,简称 dp)通过把原问题分解为相对简单的子问题的...
    99+
    2024-04-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作