动态规划 - 0-1背包问题

有一个背包,容量为c。

有n个物体X0,X1,X2,...,Xn-1,重量分别为W0,W1,W2,...,Wn-1,价值分别为V0,V1,V2,...,Vn-1。

将这n个物体中的任意几个放入背包,使得在不超过背包容量的情况下,背包中的物体总价值最大。

数学描述:

c>0

Wi>0, Vi>0, 0<=i<=n-1

求:[X0,X1,X2,...,Xn-1],其中Xi=0或1,使得X0*V0+X1*V1+...+Xn-1*Vn-1最大

约束条件:X0*W0+X1*W1+...+Xn-1*Wn-1 <= c


(1)最优子结构

假设[X0,X1,X2,...,Xn-1]是 0~n-1个物体且最大值为c 的最优解,

那么[X0,X1,X2,...,Xn-2]是 0~n-2个物体且最大值为c-(Xn-1*Wi-1) 的最优解。可用反证法证明。

(2)建立递归关系

以max[i][j]作为 0~i个物体且最大容量为j 的最优解,易知max的维度为 n*(c+1)

当i=0时:如果 j<W0,max[i][j]=0

        如果 j>=W0,max[i][j]=Vi

当i>=0时:如果 j<Wi,max[i][j]=max[i-1][j]

         如果 j>=Wi,max[i][j]=MAX(max[i-1][j], max[i-1][j-Wi]+Vi)。分为包含Xi和不包含Xi两种。

(3)自底向上,计算各个子问题的最优解

详细情况(2)中已描述

(4)求解整个问题的最优解

max[n-1][c]即是整个问题的最优解,即最大价值。

从max[n-1][c]开始向前追溯,如果 max[i][j] == max[i - 1][j],就是不包含Xi,否则就是包含Xi。


代码:

package test.xue.alg.Dynamic;

import java.util.LinkedList;

/**
 * 0-1背包问题
 * n个物体 : X0,X1,X2,...,Xn-1
 *   重量  : W0,W1,W2,...,Wn-1
 *   价值  : V0,V1,V2,...,Vn-1
 * 背包容量:c
 * 将n个物体中的任意个放入背包,使得背包中的物体总重量最大
 */
public class MaxWeight {
	public static int mw(int[] W, int[] V, int c) {
		int n = W.length;

		int[][] max = new int[n][c + 1];
		// i=0时
		for (int j = 0; j < W[0]; j++) {
			max[0][j] = 0;
		}
		for (int j = W[0]; j <= c; j++) {
			max[0][j] = V[0];
		}

		int m, tmp;
		for (int i = 1; i < n; i++) {
			for (int j = 0; j <= c; j++) {
				m = max[i - 1][j];
				if (j >= W[i]) {
					tmp = max[i - 1][j - W[i]] + V[i];
					if (tmp > m) {
						m = tmp;
					}
				}
				max[i][j] = m;
			}
		}

		traceback(W, c, max);
		return max[n - 1][c];
	}

	public static void traceback(int[] W, int c, int[][] max) {
		int n = W.length;
		int i = n - 1, j = c;
		LinkedList<Integer> list = new LinkedList<Integer>();
		for (; i > 0; i--) {
			if (max[i][j] != max[i - 1][j]) {// 如果最大值为j的时候,有没有Xi价值都一样,那就是没有Xi
				list.addFirst(i);
				j -= W[i];
			}
		}
		if (j >= W[0])
			list.addFirst(0);
		System.out.println(list);
	}

	public static void main(String[] args) {
		int[] W = { 2, 2, 6, 5, 4 }; // 重量
		int[] V = { 6, 3, 5, 4, 6 }; // 价值
		int c = 10; // 背包容量
		int max = mw(W, V, c);
		System.out.println("max : " + max);
	}
}

输出:

[0, 1, 4]
max : 15

意为:将X0,X1,X4装入背包时的总价值最大,为15.






  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值