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

题目描述

给定一个背包,它的承重是c。给定若干物品,每个物品的重量用w[i]来表示(表示第i个物品的重量),每个物品的价值用v[i]来表示(表示第i个物品的价值)。现在要求,从给定的物品中选择若干物品放入背包,要求重量之和不能大于背包的承重c,且价值最大。

  • 注意:每个物品的状态只能是装入背包或者是不装入背包,且只能装入一次。

分析

先给个短例子,假设背包承重为6,可选择的物品共有种,重量依次为【1,3,5】,每个物品的价值依次是【5,6,10】。用dp[i][j]来表示,当可选物品为i,i+1,…,3时,背包承重为j时所选择物品的最优值。dp[1][6]即为所要求的值。
我们开始进行选择,假设我选择了第一件物品放入背包,那么这件物品就要从可选择物品中去掉,背包的承重减一即c=6-1=5,所获得的价值是5,dp[1][6]=dp[2][5]+5;接下来,我们就要从剩余的物品中选择,即求dp[2][5]。但是我们如果不选择第一件物品,背包得承重不会发生变化,那么我们要求的就是dp[2][6],即dp[1][6] = dp[2][6]。但是我们怎么知道选择哪一种呢?要进行比较取两种中结果更大的一个dp[1][6]=max{dp[2][6],dp[2][5]+5}。
可见,我们要求的母问题,可以用它的子问题表示,且子问题和母问题是同一类问题。这种问题具有最优子结构,且母问题的解依赖子问题的解。于是我们想到了用动态规划来求解。动态规划最重要的就是找到问题的转移方程。比如上面的方程dp[i][j] = max{dp[i+1][j],dp[i+1][j-w[i]]+v[i]}就是问题的转移方程。有了转移方程还不够,我们还得确定问题的边界,边界是指当子问题到达一定程度之后,就能直接得到答案,而不需要继续划分子问题。比如dp[3][0]=0,这时,可选的物品为第三个物品,但是此时背包承重为0,这时就不能将物品放入背包中,dp[3][6],此时背包承重为6,我们就可以将物品放入背包。

  • 有了边界有了状态转移方程,我们就可以进行编程了。

    状态转移方程:dp[i][j] = max{dp[i+1][j],dp[i+1][j-w[i]]+v[i]}

	public static int maxValue(int[] v,int[] w,int c,int n) {
		int dp[][]= new int[n+1][c+1];
		int crisis = min(c,w[n]);
		//确定边界值
		for(int j=0;j<crisis;j++) {
			dp[n][j] = 0;
		}
		for(int j=w[n];j<=c;j++) {
			dp[n][j] = v[n];
		}
		//动态规划
		for(int i=n-1;i>=1;i--) {
			crisis = min(c,w[i]);
			for(int j=0;j<crisis;j++) {
				dp[i][j] = dp[i+1][j];//当前背包容量小于当第i个物品的重量
			}
			for(int j=w[i];j<=c;j++) {
				dp[i][j] = max(dp[i+1][j],dp[i+1][j-w[i]]+v[i]);//当前背包容量大于或等于第i个物品的重量
			}
		}
		return dp[1][c];
	}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值