0-1背包问题

2023-05-16

0-1背包问题

      甲欲出去旅游,可携带20公斤的行李,已知甲想带的5件行李的重量及其在旅行中产生的效益如下表所示:

行李编号

I

II

III

IV

V

重量/千克

6

4

8

8

4

行李效益

8

4

8

10

2

为使所带的行李在旅行中产生最大的效益,请问甲应该带哪几件行李?

【分析】

       经典的0-1背包问题。

       我们先用回溯法解决该问题,穷举所有可能性,当然进行适当的“剪枝”提高效率。在所有的可能性中寻找最优方案,并记录最优方案和最优值。

 

       我们再考虑用动态规划解决问题:

设甲可携带的行李重量为c,每个行李的重量为w(i)1 <= i <= n)(表示第i个行李的重量),而每个行李对应的效益为v(i) (1 <= i <= n)(表示第i个行李的效益),用x(i)来表示第i个行李是否应该携带,当x(i)1时,表示携带,当x(i)0时,表示不携带。

则该问题的目标函数为

       max z = ∑x(i)v(i) (1 <= i <= n) (i = 1, 2, 3, ……, n对应xv的乘积的和)

约束条件为

       ∑w(i)x(i) <= c;

       x(i) ∈ {0, 1}, 1 <= i <= n;

 

       我们可以证明该问题具有最优子结构性质,即规模为n的问题的最优解必由它的子问题– 1最优解得到。

       例如:我们已知前– 1个行李的最优携带方式,现在我们要求有k个行李时的最优解(当然这k个行李包含前面所提到的– 1个行李),此时k个行李时的最优解包含前 – 1个行李的最优解。

       此时我们根据运用动态规划构建子问题间的递推关系:

设该问题的子问题

目标函数 maxv(k)x(k) (kin)

约束条件 ∑w(k)x(k) <= j (kin)

               x(k) ∈ {0, 1}, i <= k <= n;

的最优值为m(i, j),即可携带的行李重量为j,可选择的行李编号为in时的最优值。则有

当i = n时,m(i, j) = m(n, j);

(表示可携带的行李重量为j,可选择的行李编号只有n,即只有一个行李可供选择)

       当 j <= c 时, m(n, j) = 0;

       (表示可携带的行李重量不足以携带编号为n的行李,那么它的最优值为0)

       当 j > c 时, m(n, j) = v(j);

       (表示可携带的行李重量大于这个编号为n的行李重量,即我们可以携带该行李)

 

当 i != n时,

       当0 <= j <= w(i)时,m(i, j) = m(i + 1, j);

       (表示当前可携带的行李重量为j,判断编号为i的行李是否可选,当该行李的重量大于可携带的行李重量时,该行李不能被携带,即它的最优值应该为除去行李i后考虑可选择的行李编号从I + 1n的最优值)

       当j > w(i)时,m(i, j) = max(m(i + 1, j), m(i + 1, j – w(i)) + v(i));

       (表示当前可携带的行李重量为j,判断编号为i的行李是否可选,当该行李的重量小于可携带的行李重量时,该行李可被携带也可以不被携带,那么此时应该分情况讨论,即我们要求当该行李不被携带时所具有的最优值和当该行李被携带后的最优值,这两者中最大的为该子问题的最优值。

根据递归关系写出程序。

【程序】

用java语言编写程序,代码如下:

运用回溯法解决问题:

public class Knapsack2 {
	public static void main(String[] args) {
		int n = 5;
		int c = 20;
		int[] w = {0, 6, 4, 8, 8, 4};
		int[] v = {0, 8, 4, 8, 10, 2};
		
		int[] max = new int[1];
		max[0] = 0;
		
		int[] tx = new int[n + 1];
		int[] x = new int[n + 1];
		solve(n, c, w, v, max, tx, x, 0, 1);
		
		for(int i = 1; i < n + 1; i++)
			System.out.print(x[i] + " ");
		
		System.out.println();
		System.out.println(max[0]);
	}
	//n表示物品数量,c表示当前剩余容量,w存储各个物品的重量,v存储各个物品的价值
	//max存储最大总价值,tx存储当前的方案,x存储最优方案,cv表示当前方案的总价值,index表示当前所指向的物品编号
	public static void solve(int n, int c, int[] w, int[] v, 
			int[] max, int[] tx, int[] x, int cv, int index) {
		if(index == n + 1) {
			if(c >= 0 && cv > max[0]) {
				max[0] = cv;
				
				for(int i = 0; i < n + 1; i++)
					x[i] = tx[i];
			}
			
			return;
		}
		
		//容量不足
		if(c < 0)
			return;
		
		//表示物品不携带
		tx[index] = 0;
		solve(n, c, w, v, max, tx, x, cv, index + 1);
		
		//表示物品携带
		tx[index] = 1;
		solve(n, c - w[index], w, v, max, tx, x, cv + v[index], index + 1);
	}
}
运用动态规划解决问题:

public class Knapsack1 {
	public static void main(String[] args) {
		int[] w = {0, 6, 4, 8, 8, 4};
		int[] v = {0, 8, 4, 8, 10, 2};
		int c = 20;
		
		int n = 6;
		int[] x = new int[n];
		int[][] m = new int[100][100];
		knapsack(n - 1, w, v, c, m);
		select(n - 1, c, w, x, m);
		
		for(int i = 1; i < n; i++)
			if(x[i] == 1)
				System.out.print(i + " ");
		System.out.println();			
	}
	//求各个子问题的最优解。用二维数组m[][]来存储m(i,j)的相应值
	public static void knapsack(int n, int[] w, int[] v, int c,
			int[][] m) {
		int jMax = Math.min(w[n] - 1, c);
		
		int j;
		for(j = 1; j <= jMax; j++)
			m[n][j] = 0;
		for(j = w[n]; j <= c; j++)
			m[n][j] = v[n];
		
		for(int i = n - 1; i > 1; i--) {
			jMax = Math.min(w[i] - 1, c);
			
			for(j = 1; j <= jMax; j++)
				m[i][j] = 0;
			for(j = w[i]; j <= c; j++)
				m[i][j] = Math.max(m[i + 1][j], m[i + 1][j - w[i]] + v[i]);
		}
		
		m[1][c] = m[2][c];
		if(w[1] <= c)
			m[1][c] = Math.max(m[2][c], m[2][c - w[1]] + v[1]);
	}
	/*在剩余容量相同的情况下,从第i个物品到第n个物品中选择时,该问题的最优值如果等于从第i-1个物品到第n个物品的最优值,
	 * 说明对于从第i个物品到第n个物品中选择的问题的最优解第i个物品没有被选择
	 * 考虑只有第n个物品时,如果该问题的最优解为0,说明第n个物品没有被选择;如果该问题的最优解不为0,说明第n个物品被选择了。
	 */
	public static void select(int n, int c, int[] w, int[] x, int[][] m) {
		for(int i = 1; i < n; i++)
			if(m[i][c] == m[i + 1][c])
				x[i] = 0;
			else {
				x[i] = 1;
				c -= w[i];
			}
		
		if(m[n][c] == 0)
			x[n] = 0;
		else
			x[n] = 1;
	}
}
【结果】

回溯法:

输出最优方案,输出最优值

动态规划:

输出选取的行李编号


本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

0-1背包问题 的相关文章

  • 对称轴(Symmetry)

    Symmetry Time limit 3 000 seconds The figure shown on the left is left right symmetric as it is possible to fold the she
  • 打印队列(Printer Queue)

    Printer Queue Time limit 3 000 seconds 分析 首先记录所求时间它在队列中的位置 xff0c 用一个队列存储这些任务的优先级 xff0c 同时也创建一个队列存储对应任务一开始的位置 xff0c 那么当我们
  • 更新字典(Updating a Dictionary)

    Updating a Dictionary Time Limit 1000MS Memory Limit Unknown 64bit IO Format lld amp llu Submit Status Description In th
  • 铁轨(Rails)

    Rails Time limit 3 000 seconds Rails There is a famous railway station in PopPush City Country there is incredibly hilly
  • 矩阵链乘(Matrix Chain Multiplication)

    Matrix Chain Multiplication Time Limit 3000MS Memory Limit Unknown 64bit IO Format lld amp llu Submit Status Description
  • 天平(Not so Mobile)

    Not so Mobile Time Limit 3000MS Memory Limit Unknown 64bit IO Format lld amp llu Submit Status Description Before being
  • 下落的树叶(The Falling Leaves)

    The Falling Leaves Time Limit 3000MS Memory Limit Unknown 64bit IO Format lld amp llu Submit Status Description Each yea
  • 四分树(Quadtrees)

    Quadtrees Time Limit 3000MS Memory Limit Unknown 64bit IO Format lld amp llu Submit Status Description A quadtree is a r
  • 油田(Oil Deposits)

    Oil Deposits Time Limit 3000MS Memory Limit Unknown 64bit IO Format lld amp llu Submit Status Description The GeoSurvCom

随机推荐

  • Abbott的复仇(Abbott's Revenge)

    Abbott 39 s Revenge Time limit 3 000 seconds Abbott s Revenge Abbott s Revenge The 1999 World FinalsContest included a p
  • rockchip rk3568 openwrt修改根文件系统分区

    rk3568的openwrt根文件系统分区大小如何修改 xff1f 1 rootfs大小取决于rk356x config的配置 xff0c 默认CONFIG TARGET ROOTFS PARTSIZE 61 512 xff0c 如果需要修
  • 除法(Division)

    Division Time Limit 3000MS Memory Limit Unknown 64bit IO Format lld amp llu Submit Status Description Write a program th
  • 最大乘积(Maximum Product)

    Maximum Product Time Limit 3000MS Memory Limit Unknown 64bit IO Format lld amp llu Submit Status Description Problem D M
  • 分数拆分(Fractions Again?!)

    Fractions Again Time Limit 3000MS Memory Limit Unknown 64bit IO Format lld amp llu Submit Status Description Problem A F
  • 二叉树(Tree Recovery)

    Tree Recovery Time Limit 3000MS Memory Limit Unknown 64bit IO Format lld amp llu Submit Status Description Little Valent
  • 骑士的移动(Knight Moves)

    Knight Moves Time Limit 3000MS Memory Limit Unknown 64bit IO Format lld amp llu Submit Status Description A friend of yo
  • 单词(Play On Words)

    分析 首先需对欧拉道路有所了解 存在欧拉道路的充分条件 xff1a 对于无向图而言 xff0c 如果一个无向图是连通的 xff0c 且最多只有两个奇点 xff08 顶点的度数为奇数 xff09 xff0c 则一定存在欧拉道路 如果有两个奇点
  • 成语接龙(Idiomatic Phrases Game)

    Idiomatic Phrases Game Problem Description Tom is playing a game called Idiomatic Phrases Game An idiom consists of seve
  • DijKstra算法(单源最短路径)

    原文转载自 xff1a 梦醒潇湘love 转载原文是为了方便自己学习 xff0c 也希望能让更多读者在需要的情况下学到更多的知识 Dijkstra xff08 迪杰斯特拉 xff09 算法是典型的最短路径路由算法 xff0c 用于计算一个节
  • Floyd算法(最短路径)

    Floyd 算法允许图中有带负权值的边 xff0c 但不许有包含带负权值的边组成的回路 原文转载自 xff1a 梦醒潇湘love 上一篇文章我们通过迪杰斯特拉算法解决了从某个源点到其余各顶点的最短路径问题 从循环嵌套很容易得到此算法的时间复
  • 最爱的城市

    最爱的城市 时间限制 xff1a 1 秒 内存限制 xff1a 32 兆 特殊判题 xff1a 否 标签 Floyd最短路径 题目描述 一天小明捧着一本世界地图在看 xff0c 突然小明拿起笔 xff0c 将他最爱的那些城市标记出来 xff
  • Docker中配置Nginx多域名配置多个应用

    注意容器中是一个被隔离的空间 xff0c 可以理解为一个独立的服务器 xff0c 所以在做反向代理的时候 xff0c nginx配置不能使用localhost xff0c 可以使用link方式去访问其他容器 nginxa container
  • 八皇后问题(回溯法)

    八皇后问题 xff08 源于 刘汝佳的 算法竞赛入门经典 xff08 第2版 xff09 xff09 在棋盘上放置8个皇后 xff0c 使得它们互不攻击 xff0c 此时每个皇后的攻击范围为同行同列和同对角线 xff0c 要求找出所有解 x
  • 大整数的乘法

    大整数的乘法 xff08 这里主要讨论的是两个较大的数相乘的效率问题 xff0c 实际上并不是真正意义上的大数相乘 在java中有个BigInteger类已经可以储存大数 xff0c 并提供了大数相乘的方法了 xff09 分析 首先 xff
  • 2的次幂表示

    2的次幂表示 时间限制 xff1a 1 0s 内存限制 xff1a 512 0MB 问题描述 任何一个正整数都可以用2进制表示 xff0c 例如 xff1a 137的2进制表示为10001001 将这种2进制表示写成2的次幂的和的形式 xf
  • 扑克序列

    扑克序列 题目描述 标题 xff1a 扑克序列 A A 2 2 3 3 4 4 xff0c 一共4对扑克牌 请你把它们排成一行 要求 xff1a 两个A中间有1张牌 xff0c 两个2之间有2张牌 xff0c 两个3之间有3张牌 xff0c
  • 分糖果

    分糖果 时间限制 xff1a 1 0s 内存限制 xff1a 256 0MB 问题描述 有n个小朋友围坐成一圈 老师给每个小朋友随机发偶数个糖果 xff0c 然后进行下面的游戏 xff1a 每个小朋友都把自己的糖果分一半给左手边的孩子 一轮
  • 最长公共子序列(LCS)

    最长公共子序列LCS问题 给定2个序列X和Y xff0c 当另一序列Z既是X的子序列又是Y的子序列时 xff0c 称Z是序列X和Y的公共子序列 给定X 61 x1 x2 xm 和Y 61 y1 y2 yn xff0c 请找出X和Y的最长公共
  • 0-1背包问题

    0 1背包问题 甲欲出去旅游 xff0c 可携带20 公斤的行李 xff0c 已知甲想带的 5 件行李的重量及其在旅行中产生的效益如下表所示 xff1a 行李编号 I II III IV V 重量 千克 6 4 8 8 4 行李效益 8 4