动态规划求解01背包问题

近期事情多,且老师讲动态规划讲得云里雾里。。于是又没有跟上进度,菜鸡终于要来填坑了。

动态规划

动态规划和分治法有些相像,都是把一个问题分成了很多子问题来求解,但是不同的是动态规划会记忆之前解决的子问题的结果,避免了重复计算。判断一个问题是否能用动态规划求解,要看它是否能划分成合适的子问题,然后写出递推关系式。

动态规划得到的解一定是最优解。

01背包问题
(1)问题描述:
现有n件物品,每件都有对应的重量(w)和价值(v),有一个给定容量(C)的背包,怎么样才能在背包里装入具有最大价值总和的东西?
具体例子:
在这里插入图片描述
(2)问题分析:
突然想到之前看数模书的时候提到的一种思路——引入0-1变量,化为整数规划问题。
模型建立:已知n件物品的重量为W1~Wn ,价值为V1 ~Vn,用X1 ~Xn来表示是否选了这件物品放入背包,Xi为0或1。
决策目标即为:MAX(V1X1+V2X2+…+VnXn)
约束条件即为:(W1X1+W2X2+…+WnXn) ≦ C
抖机灵用lingo求了下解。。
在这里插入图片描述
好了言归正传。。
(3)寻找子问题和建立递推关系式
这里采用自底向上的思路
定义子问题:在前i个物品里面挑选总重量不大于W(W<=C)的物品,记最优值为M(i, W),则对于第i个物品来说就有两种情况:
①Wi>W,装不下了,则M(i, W)=M(i-1, W);
②Wi<=W,那么就要选择装不装,则M(i, W)=max{M(i-1, W) , M(i-1, W-Wi)+Vi}
M(i-1, W-Wi)即为第i个物品装入之前的最优值,结果是装了第i个物品。
接下来就是初始化的问题了,还是看源代码吧。
(4)源代码:

public class FindMax {	
	public static void main(String[] args){
		int capacity=11;
		int item_num=5;
		int[][] M = new int[item_num+1][capacity+1];
		int[] w={0,1,2,5,6,7};
		int[] v={0,1,6,18,22,28};
		int i,j;
		for(i=0;i<=capacity;i++){
			M[0][i]=0;
		}
		for(j=0;j<=item_num;j++){
			M[j][0]=0;
		}
		for(i=1;i<=item_num;i++){
			for(j=1;j<=capacity;j++){
				if(w[i]>j){
					M[i][j]=M[i-1][j];
				}
				else{
					M[i][j]=Math.max(M[i-1][j], M[i-1][j-w[i]]+v[i]);
				}
			}
		}
		for(i=0;i<=item_num;i++){
			for(j=0;j<=capacity;j++){
				System.out.print(M[i][j]+ "\t");
			}
			System.out.println("");
		}
	}
}

结果截图如下:
在这里插入图片描述
最优解为40,那么怎么知道是哪几件物品被选中了呢?我们要从表的右下角往回看,M(5, 11)=M(4, 11)=40且M(4,11)不等于M[3,11],说明选了4号物品;减去4号物品的重量40-22=18,M(3, 5)=18且M(3,5)不等于M(2, 5)且M(3,5)=M(4,5)=M(5,5),说明第三件物品被选择了,减去三号物品的重量40-22-18=0;说明被选中的就是3号和4号。

今天就写到这里吧。

  • 4
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值