01背包

01背包概述

01背包是在M件物品取出若干件放在空间为W的背包里,每件物品的体积为W1,W2至Wn,与之相对应的价值为P1,P2至Pn。01背包是背包问题中最简单的问题。01背包的约束条件是给定几种物品,每种物品有且只有一个,并且有权值和体积两个属性。在01背包问题中,因为每种物品只有一个,对于每个物品只需要考虑选与不选两种情况。如果不选择将其放入背包中,则不需要处理。如果选择将其放入背包中,由于不清楚之前放入的物品占据了多大的空间,需要枚举将这个物品放入背包后可能占据背包空间的所有情况。

分析方法

01背包问题可以看作是决策一个序列(x1, x2, …, xn),对任一变量xi的决策是决定xi=1还是xi=0。在对xi-1决策后,已确定了(x1, …, xi-1),在决策xi时,问题处于下列两种状态之一:
(1)背包容量不足以装入物品i,则xi=0,背包不增加价值;
(2)背包容量可以装入物品i。
在(2)的状态下,物品i有两种情况,装入(则xi=1)或不装入(则xi=0)。在这两种情况下背包价值的最大者应该是对xi决策后的背包价值。
令V(i, j)表示在前i(1≤i≤n)个物品中能够装入容量为j(1≤j≤C)的背包中的物品的最大值,则可以得到如下动态规划函数:
①V(i, 0)= V(0, j)=0    (把前面i个物品装入容量为0的背包和把0个物品装入容量为j的背包,得到的价值均为0 )

例题

有5个物品,其重量分别是{2, 2, 6, 5, 4},价值分别为{6, 3, 5, 4, 6},背包的容量为10。问如何挑选物品放入背包,使得背包中的价值最大?

思路

根据动态规划函数,用一个(n+1)×(C+1)的二维表V,V[i][j]表示把前i个物品装入容量为j的背包中获得的最大价值。

 初始化0行、0列,然后一行一行计算分析可得出上表。

import java.util.Scanner;
public class Main {
	public static void main(String[] args) {
		Scanner cin = new Scanner(System.in);
		
		int n = cin.nextInt(); //物品数
		int m = cin.nextInt(); //背包容量
		
		int[] v = new int[n+5]; //物品价值
		int[] w = new int[n+5]; //物品重量
		int[][] f = new int[n+5][m+5]; //前i个物品装入容量为j的背包中的最大价值
		for(int i=1; i<=n; i++) w[i] = cin.nextInt();
		for(int i=1; i<=n; i++) v[i] = cin.nextInt();
		
		//初始化
		for(int i=0; i<=n; i++) f[i][0] = 0;
		for(int i=0; i<=m; i++) f[0][i] = 0;
		
		for(int i=1; i<=n; i++) {
			for(int j=1; j<=m; j++) {
				if(w[i] > j) f[i][j] = f[i-1][j];
				else f[i][j] = Math.max(f[i-1][j], f[i-1][j-w[i]] + v[i]);
			}
		}
		
		boolean[] x = new boolean[n+5]; //标记物品i是否加入背包
		for(int i=n,j=m; i>=1; i--) {
			if(f[i][j] > f[i-1][j]) {
				x[i] = true;
				j -= w[i];
			}else {
				x[i] = false;
			}
		}
		
		System.out.println("最大价值为:" + f[n][m]); //最大价值
		System.out.print("需要放入背包的物品编号:");
		for(int i=1; i<=n; i++) {
			if(x[i] == true)
				System.out.print(i+" ");
		}
		
		cin.close();
	}
}
/**

5 10
2 2 6 5 4
6 3 5 4 6

*/

运行截图


如有错误或不合理的地方,敬请指正~

加油!!

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值