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

问题描述:给定n种物品和一背包。物品i的重量是wi,其价值为vi,背包的容量为C。问应如何选择装入背包的物品,使得装入背包中物品的总价值最大?
0-1背包问题是一个特殊的整数规划问题。

0-1背包问题的目标函数约束条件如下:
1
其最优值为m(i,j),即m(i,j)背包容量为j,可选择物品为i,i+1,…,n时0-1背包问题的最优值。由0-1背包问题的最优子结构性质,可以建立计算m(i,j)的递归式如下。
2

例如:有编号分别为1,2,3,4,5的五件物品,它们的重量分别是2,2,6,5,4,它们的价值分别是6,3,5,4,6,现在给你个承重为10的背包,如何让背包里装入的物品具有最大的价值总和?
3
代码如下:

public class test3_9 {
	public static void knapsack(int[] v,int[] w,int c,int[][] m){
		int n = v.length-1;
		//若w[n]>c表示第n个物品重量大于当前剩余容量c,则选择不装(jMax=c,则第一个for循环m[n][0]~m[n][c]=0)
		int jMax = Math.min(w[n]-1, c);  
		//1.求m[n][j]
		for(int j=0;j<=jMax;j++)
			m[n][j] = 0;
		for(int j=w[n];j<=c;j++)
			m[n][j] = v[n];
		//2.求m[i][j]
		for(int i=n-1;i>0;i--){  //从倒数第二个物品向前迭代,共迭代n-2次
			jMax = Math.min(w[i]-1, c);
			for(int j=0;j<=jMax;j++)
				m[i][j] = m[i+1][j];
			for(int j=w[i];j<=c;j++)
				m[i][j] = Math.max(m[i+1][j], m[i+1][j-w[i]]+v[i]);
		}
		//3.求m[0][c]
		m[0][c] = (w[0]>c)? m[1][c]: Math.max(m[1][c], m[1][c-w[0]]+v[0]);
	}
	public static void traceback(int[][] m,int[] w,int c,boolean[] x){
		int n = w.length-1;
		for(int i=0;i<n;i++)
			if(m[i][c]==m[i+1][c]) //若相等则说明,第i个物品没有放到背包里
				x[i] = false;
			else{
				x[i] = true;
				c -= w[i];
			}
		x[n] = (m[n][c]>0)? true:false;  //最后一个物品有价值说明最后一个物品放进了背包
	}
	public static void main(String[] args) {
		int[] w = {2,2,6,5,4};
		int[] v = {6,3,5,4,6};
		int n = v.length;  //物品的数量
		boolean[] x = new boolean[n];
		int c = 10;
		int[][] m = new int[n][c+1];  //m[][0]~m[][c]
		knapsack(v,w,c,m);
		traceback(m,w,c,x);
		for(int i=0;i<v.length;i++){
			for(int j=0;j<=c;j++)
				System.out.print(m[i][j]+" ");
			System.out.println();
		}
		for(int i=0;i<n;i++)
			System.out.println("第"+(i+1)+"个物品是否放入背包:"+x[i]+" ");
	}
}

输出结果:

第1个物品是否放入背包:true 
第2个物品是否放入背包:true 
第3个物品是否放入背包:false 
第4个物品是否放入背包:false 
第5个物品是否放入背包:true 

总结:0-1背包问题程序求解三大步骤如下
①求m[n][j]
②求m[i][j]
③求m[0][c]

时间复杂度为:O(n*c)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

SL_World

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值