0-1背包问题(0-1 knapsack problem)c++实现
文章目录
- 1 问题描述
- 2 基本原理
- 3代码实现
1 问题描述
有n个物品,它们有各自的重量和价值,现有一给定最大载重的背包,如何让背包里装入的物品具有最大的价值总和而又不超过最大载重?
比如:
商品 | 1 | 2 | 3 | 4 | 5 |
---|---|---|---|---|---|
重量 | 1 | 2 | 3 | 4 | 5 |
价值 | 3 | 4 | 5 | 6 | 7 |
假设背包最大载重为8,可以求得以下两种最优方案
商品1 商品2 商品5
总价值:14
总重量:8 <= 最大载重
商品1 商品3 商品4
总价值:14
总重量:8 <= 最大载重
2 基本原理
定义数组V[0…n][0…maxWeight]
其中,n表示商品的总数,maxWeight表示背包的最大载重量。
定义V[i][w]为包含前i件商品且最大载重为w时的子问题的最优方案的总价值。
只需要讨论当前商品i是否可能在当前子问题的最优方案中便可以得到以下递推式:
若 weigth[i] > w, 即当前商品i太重了,故不可能出现在当前子问题的最优方案里,因此
V[i][w] = V[i-1][w]
//若 weigth[i] <= w ,则说明当前商品i可能在当前子问题的最优方案中,因此需要做比较选择,故有
V[i][w] = max( V[i-1][w] , V[i-1][w-weigth[i]] + value[i] )
3代码实现
利用上面的递推式便能使用动态规划算法解决问题!
c++代码如下:
//Albert Chow 2020.08.30
# include <iostream>
using namespace std;/***********************************************************************************/
//用于动态创建二维数组
//利用了模板
template<typename T>
T** buildArray2D(int row, int column)
{T* p = new T[row * column]; //开辟一片临时空间T** a = new T * [row]; //创建行指针for (int i = 0; i < row; i++){a[i] = p + column * i; //给行指针赋值}return a;};template<typename T>
void deleteArray2D(T** a)
{delete[] * a;delete[] a;
}
/***********************************************************************************///0-1背包问题算法//简单版本,用于理解算法
int knapsack_0_1_v1(int n, int* weigth, int* value, int maxWeight)
{int** V = buildArray2D<int>(n+1, maxWeight+1); //动态创建一个二维数组//其中A[i][w] 表示 包含前i件商品,最大重量为w时的子问题的最大价值//因此可分最优方案包不包含当前商品i而得到如下的递推式://若 weigth[i] > w, 即当前商品i太重了,故不可能出现在当前子问题的最优方案里,因此//V[i][w] = V[i-1][w]//若 weigth[i] <= w ,则说明当前商品i可能在当前子问题的最优方案中,因此需要做比较选择//V[i][w] = max( V[i-1][w] , V[i-1][w-weigth[i]] + value[i] )//根据以上的递推式设计自底向上的dp算法如下:int i,w;//对V做下初始化for (w = 0; w <= maxWeight; w++)V[0][w] = 0;for (i = 1; i <= n; i++)V[i][0] = 0;for(i = 1;i<=n;i++)for (w = 1; w <= maxWeight; w++){if (weigth[i -1] > w) //当前商品大于背包容量时的递推式{V[i][w] = V[i - 1][w]; }else //当前商品可能出现在最优解里面的递推式{//V[i][w] = max( V[i-1][w] , V[i-1][w-weigth[i]] + value[i] )//注意cpp中数组下标从0开始if ( V[i - 1][w] > (V[i - 1][w - weigth[i - 1]] + value[i - 1]) ){V[i][w] = V[i - 1][w];}else{V[i][w] = V[i - 1][w - weigth[i - 1]] + value[i - 1];}}}int res = V[n][maxWeight];deleteArray2D<int>(V);//手动释放内存return res;
}//原理同v1,只是在内存上作了优化
int knapsack_0_1_v2(int n, int* weigth, int* value, int maxWeight)
{int* V = new int[maxWeight + 1];int i, w;//对V做下初始化for (w = 0; w <= maxWeight; w++)V[w] = 0;for (i = 1; i <= n; i++)//为了防止数据覆盖,这里w采用逆序//由于w < weigth[i - 1]时 无需更新数组,因此w的遍历只到weigth[i - 1]for (w = maxWeight; w >= weigth[i - 1]; w--) { if (V[w - weigth[i - 1]] + value[i - 1] > V[w]){V[w] = V[w - weigth[i - 1]] + value[i - 1];}}int res = V[maxWeight];delete[] V;return res;
}//定义一个结构体,用于函数返回多个变量
typedef struct
{int val;bool** choice;
} RES;//原理同v1,只是为重现最优解做了一些修改
RES knapsack_0_1_v3(int n, int* weigth, int* value, int maxWeight)
{int** V = buildArray2D<int>(n + 1, maxWeight + 1); //动态创建一个二维数组bool **choice = buildArray2D<bool>(n, maxWeight);int i, w;//对V做下初始化for (w = 0; w <= maxWeight; w++)V[0][w] = 0;for (i = 1; i <= n; i++)V[i][0] = 0;for (i = 1; i <= n; i++)for (w = 1; w <= maxWeight; w++){if (weigth[i - 1] > w) //当前商品大于背包容量时的递推式{V[i][w] = V[i - 1][w];choice[i -1][w -1] = 0; //注意c语言下标从0开始}else //当前商品可能出现在最优解里面的递推式{//V[i][w] = max( V[i-1][w] , V[i-1][w-weigth[i]] + value[i] )//注意cpp中数组下标从0开始if (V[i - 1][w] > (V[i - 1][w - weigth[i - 1]] + value[i - 1])){V[i][w] = V[i - 1][w];choice[i - 1][w - 1] = 0;}else{V[i][w] = V[i - 1][w - weigth[i - 1]] + value[i - 1];choice[i - 1][w - 1] = 1;}}}RES res;res.val = V[n][maxWeight];res.choice = choice;//手动释放内存deleteArray2D<int>(V);return res;
}//原理同v2,只是为重现最优解做了一些修改,注意多与v3对比
RES knapsack_0_1_v4(int n, int* weigth, int* value, int maxWeight)
{int* V = new int[maxWeight + 1];bool** choice = buildArray2D<bool>(n, maxWeight);int i, w;//对V做下初始化for (w = 0; w <= maxWeight; w++)V[w] = 0;for (i = 1; i <= n; i++){//为了防止数据覆盖,这里w采用逆序//由于w < weigth[i - 1]时 无需更新数组,因此w的遍历只到weigth[i - 1]for (w = maxWeight; w >= weigth[i - 1]; w--){if (V[w - weigth[i - 1]] + value[i - 1] > V[w]){V[w] = V[w - weigth[i - 1]] + value[i - 1];choice[i - 1][w - 1] = 1;}elsechoice[i - 1][w - 1] = 0;}for (w = weigth[i - 1]-1; w>=1; w--) //补零choice[i -1][w -1] = 0;}RES res;res.val = V[maxWeight];res.choice = choice;delete[] V;return res;
}//仿照算法导论p225的程序得到的
void printKnapsack(bool** choice, int *weight,int i,int w)
{if (i == 0 || w == 0)return;if (choice[i -1][w -1] == 1){printKnapsack(choice, weight, i - 1, w - weight[i - 1] );cout << "商品" << i << " ";}else{printKnapsack(choice, weight, i - 1, w);}
}int main()
{//可以自己修改数据验证算法是否正确// 1 2 3 4 5 6 7 8 9 10int weight[] = {1, 2, 3, 4, 5};int value[] = {3, 4, 5, 6, 7};int n = sizeof(weight)/sizeof(weight[0]);int maxWeight = 8;/************************************************************************/int r1 = knapsack_0_1_v1(n,weight, value, maxWeight);cout << r1 << endl;int r2 = knapsack_0_1_v2(n, weight, value, maxWeight);cout << r2 << endl;RES r3 = knapsack_0_1_v3(n, weight, value, maxWeight);cout << r3.val << endl;printKnapsack(r3.choice, weight, n, maxWeight);deleteArray2D<bool>(r3.choice);cout << endl;RES r4 = knapsack_0_1_v4(n, weight, value, maxWeight);cout << r4.val << endl;printKnapsack(r4.choice, weight, n, maxWeight);deleteArray2D<bool>(r4.choice);cout << endl;return 0;
}
0-1背包问题(0-1 knapsack problem)c++实现相关推荐
- 动态规划法(四)0-1背包问题(0-1 Knapsack Problem)
继续讲故事~~ 转眼我们的主人公丁丁就要离开自己的家乡,去大城市见世面了.这天晚上,妈妈正在耐心地帮丁丁收拾行李.家里有个最大能承受20kg的袋子,可是妈妈却有很多东西想装袋子里,已知行李的编 ...
- Knapsack Problem
背包九讲 0-1 knapsack problem 01背包-牛客网 已知一个背包最多能容纳体积之和为V的物品,现有 n 个物品,第 i 个物品的体积为 vi , 重量为 wi,求当前背包最多能装多大 ...
- [Algorithmic Toolbox学习笔记][week6]0/1 Knapsack Problem
问题描述 具体的问题描述请参考以下链接: [Algorithmic Toolbox学习笔记][week3]战利品的最大价值_Karen_AMPM的博客-CSDN博客假设小偷有一个背包只能放下一定重量的 ...
- Dynamic Programming 01 —knapsack problem(动态规划背包问题)
首先引入动态变化的含义:为什么要有动态规划? Introduction: 从斐波那契函数的递归中我们发现,在例子求fib(7)的过程中,我们需求得fib(5)和fib(6),而我们在求fib(6)的时 ...
- C#,背包问题(Knapsack Problem)贪心算法的源代码
背包问题(KnapSack Problem)的相关算法是常用的规划算法. 一.什么是背包问题? 背包的问题是,你有一个"袋子",可以装有限数量的物品,鉴于你有一组物品可以从每个物品 ...
- 算法设计与分析实验二:动态规划法实现TSP问题和0/1背包问题
[实验目的] 1.熟练掌握动态规划思想及教材中相关经典算法. 2.使用动态规划法编程,求解0/1背包问题和TSP问题. TSP问题 一.实验内容: TSP问题是指旅行家要旅行n个城市,要求每个城市经历 ...
- Python多维约束(重量+体积+次数)背包问题(Knapsack Problem)
问题描述:1.一个背包,往里装东西,物品重量w(weight)对应为[2,3,4,7] ,价值va(value)对应为[1,4,7,12] ,如果你的最大承重为20,每个物品可装次数不限,求你能装入背 ...
- 0/1背包问题---C++动态规划法
[问题] 给定n种物品和一个背包,物品i(1≤i≤n)的重量是,其价值为,背包容量为,对于每种物品只有两种选择:装入背包或者不装入背包.如何选择装入背包的物品,使得装入背包中物品的总价值最大? [想法 ...
- C语言动态规划法解决0/1背包问题(详细解答)
动态规划法解决0/1背包问题(详细解答) 首先让我们回顾一下动态规划法的使用规则: 一..动态规划法的实现思路: 1.划分子问题:将元问题分解为若干个子问题,每一个子问题对应一个决策,并且子问题之间具 ...
最新文章
- SSRS配置2:加密管理
- Openstack-M版(双节点)热迁移记录
- 关于图片按比例自适应缩放
- 记录 关于浏览器跨域和设置默认浏览器的问题
- 边框回归的损失函数_分类损失函数,边框回归损失函数
- 邹建老大写的经典SQL
- top-1和top-5正确率与错误率以及目标检测评价指标
- 用户与组管理,磁盘管理
- 四个DBHelper实现
- python ffmpeg剪辑视频_FFMPEG剪辑大法
- mumu模拟器Android版本才6,mumu模拟器老版本
- 《自然语言处理简明教程》读书笔记:第十四章 文本数据挖掘
- 传输线模式<TEM TE TM EH HE>
- SysAnti.exe和autorun.inf病毒的查杀
- CSS3炫酷的发光文字 可自定义文字色彩
- 如何在地图上显示多个红包商店 vue
- 在线制作平台H5制作
- 【设计模式】工厂模式(Factory Pattern)
- 基于Springboot+Mybatisplus+Vue的科研项目管理系统
- centos8操作系统初始化设置
热门文章
- linux网络操作系统电大考试,国开2020年秋《linux网络操作系统》形考任务题库大全...
- 16m色真彩调色板设计制作
- 【无标题】ubuntu添加文件到mkinitramfs命令生成的initramfs中
- 使用c#实现爬虫技术
- android的定位(2)
- 查看QQ是否隐身,轻而易举。 - [工具+源码]
- 实验四 数码管显示设计与仿真
- 【NLP+图神经网络+推荐领域】2020年最新综述性文章推荐
- Pandas单层索引多层索引
- Google面对点击欺诈拷问 广告主拟诉诸法律