基于动态规划方法求解0-1背包问题

基于动态规划方法求解0-1背包问题

问题描述

现有n个物品,1个背包。对物品i,其价值为 v i v_i vi ,重量为 W i W_i Wi,背包的容量为 W W W,如何选取物品使得背包里转入物品的总价值最大?

在约束条件为:选取物品的重量小于等于背包重量的情况下,尽可能让背包中物品的总价值最大。

算法设计

根据问题描述,约束条件为,目标函数为:

在满足约束条件的情况下,找到是目标函数最大的解。

使用两个等长的一维数组存储物品的重量 w e i g h t s [ n ] weights[n] weights[n]和价值 v a l u e s [ n ] values[n] values[n],这里第 i i i个物品的重量就是 w e i g h t s [ i ] weights[i] weights[i],价值就是 v a l u e s [ i ] values[i] values[i]

使用动态规划的方式求解该问题,构建二维数组 d p [ n + 1 ] [ W + 1 ] dp[n+1][W+1] dp[n+1][W+1]来记录中间过程的最优解,这里 d p [ i ] [ j ] dp[i][j] dp[i][j]表示当背包容量为 j j j时,装前 i i i个物品的最优解。

描述算法

依次考虑前 i − 1 i-1 i1个物品装入背包的最优解,那么装入前 i i i个物品的最优解就是在前 i − 1 i-1 i1个物品的最优解上进行构建

如果只考虑第i件物品放还是不放,那么就可以转化为一个只涉及到前i-1个物品的问题。如果不放第i个物品,那么问题就转化为“前i-1件物品放入容量为j的背包中的最优价值组合”,对应的值为 d p [ i − 1 , j ] dp[i-1,j] dp[i1,j]。如果放第i个物品,那么问题就转化成了“前i-1件物品放入容量为 j − w i j-w_i jwi的背包中的最优价值组合”,此时对应的值为 d p [ i − 1 , j − W i ) ] + v i dp[i-1,j-W_i)]+v_i dp[i1,jWi)]+vi

  • d p [ i ] [ 0 ] = d p [ 0 ] [ j ] = 0 dp[i][0]=dp[0][j]=0 dp[i][0]=dp[0][j]=0

  • 如果第 i i i个 物品重量大于背包总重量 j j j,那么 d p [ i ] [ j ] = d p [ i − 1 ] [ j ] dp[i][j]=dp[i-1][j] dp[i][j]=dp[i1][j]

  • 如果第 i i i个 物品重量小于等于背包总重量 j j j,那么 d p [ i ] [ j ] = m a x ( d p [ i − 1 ] [ j ] , d p [ i − 1 ] [ j − w e i g h t s [ i ] ] + v a l u e s [ i ] dp[i][j]=max(dp[i-1][j],dp[i-1][j-weights[i]]+values[i] dp[i][j]=max(dp[i1][j],dp[i1][jweights[i]]+values[i]

    01PACKAGE(values[n],weights[n],W) // W为背包容量
    	dp[n+1][W+1]
    	for i=0 to n:
    		do dp[i][0] = 0
    	for j=0 to W:
    		do dp[0][j] = 0
    	for i=1 to n:
    		for j=1 to W:
    			do
    			if j < weights[i]:
    				dp[i][j]=dp[i-1][j]
    			else
    				dp[i][j]=
    					max(dp[i-1][j],dp[i-1][j-weights[i]]+values[i])
    	return C
    

算法的正确性证明

假设 ( x 1 , x 2 , … , x n ) (x_1,x_2,…,x_n) (x1x2xn)是01背包问题的最优解,则有 ( x 2 , x 3 , … , x n ) (x_2,x_3,…,x_n) (x2x3xn)是其子问题的最优解,假设 ( y 2 , y 3 , … , y n ) (y_2,y_3,…,y_n) (y2y3yn)是上述问题的子问题最优解,则有 ( v 2 y 2 + v 3 y 3 + … + v n y n ) + v 1 x 1 > ( v 2 x 2 + v 3 x 3 + … + v n x n ) + v 1 x 1 (v_2y_2+v_3y_3+…+v_ny_n)+v_1x_1 > (v_2x_2+v_3x_3+…+v_nx_n)+v_1x_1 (v2y2+v3y3++vnyn)+v1x1>(v2x2+v3x3++vnxn)+v1x1。说明(X_1,Y_2,Y_3,…,Y_n)才是该01背包问题的最优解,这与最开始的假设(X_1,X_2,…,X_n)是01背包问题的最优解相矛盾,故01背包问题满足最优性原理

至于无后效性,其实比较好理解。对于任意一个阶段,只要背包剩余容量和可选物品是一样的,那么我们能做出的现阶段的最优选择必定是一样的,是不受之前选择了什么物品所影响的。即满足无后效性

算法复发性分析

时间复杂度:

空间复杂度:

算法实现与测试

public class Main {
    public static void main(String[] args) {
        int weights[] = {2, 6, 3, 4, 2, 8, 2, 4, 7, 5, 1};
        int values[] = {10,23,5,34,23,17,22,32,12,15,32};
        int W=15;

        int dp[][] = packet01(W,weights,values);
        int res[] = new int[W];
        int j = W;
        for (int i = weights.length; i > 0; i--) {
            if(dp[i][j] == dp[i-1][j])
                res[i-1] = 0;
            else{
                res[i-1] = 1;
                j -= weights[i-1];
            }
        }
        System.out.println("res: "+dp[weights.length][W] );
        System.out.println("packets: ");
        for (int i = 0; i < W; i++) {
            System.out.print(res[i] +" ");
        }

    }
    public static int[][] packet01(int W, int weights[], int values[]) {
        int n = weights.length;
        int [][]dp = new int[n+1][W+1];

        for (int i = 0; i <= n; i++) {
            dp[i][0] = 0;
        }
        for (int j = 0; j <= W ; j++) {
            dp[0][j] = 0;
        }

        for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= W; j++) {
                int currentItem = i-1;
                if(j < weights[currentItem]){
                    dp[i][j] = dp[i-1][j];
                } else {
                    dp[i][j] = Math.max(dp[i-1][j],
                            dp[i-1][j-weights[currentItem]] + values[currentItem]);
                }
            }
        }
        return dp;
    }
}

测试:

res: 153
packets: 
1 0 0 1 1 0 1 1 0 0 1 0 0 0 0 

心得体会

动态规划算法通常是用来解决某种最优性质的问题。基本思想是将带求解问题划分为若干个子问题,先求解子问题,然后从子问题的解得到原问题的解。动态规划与分治法的区别在于,动态规划的子问题可能是互相重叠的重复计算的,分治法则是相互独立的。可以用一个表来记录子问题是否已经求解,这样可以避免重复求解。

动态规划需要满足:

  • 最优化原理,一个最优化策略的子策略一定是最优的,就是满足最优子结构的性质。

  • 无后效性,一个阶段以前各阶段的状态无法直接硬性它未来的决策,只能通过当前的这个状态。

  • 重叠性,就是记录已经解决过的问题,需要存储已经解决过的问题,空间复杂度比较大,是一种以空间换时间的算法。

动态规划的难点在于,如何根据问题的最优子结构的性质,构造动态规划方法中的递归公式或动态规划方程。就比如本问题中,如何设计这个方程才是难点所在。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值