背包问题详解

1.0-1背包问题

问题描述:有N件物品和一个容量为V的背包。第i件物品的重量是w[i],价值是p[i]。求解将哪些物品装入背包可使这些物品的总重量不超过背包容量,且价值总和最大。

思路:每种物品仅有一件,可以选择放或不放。

F[i,v]表示前i件物品放入一个容量为v的背包可以获得的最大价值。状态转移方程为:

F[i,v]=max{F[i-1,v],F[i-1,v-w[i]]+p[i]}

    将前i件物品放入容量为v的背包中,如果只考虑第i件物品的策略(放或者不放),那么就可以转化为一个只和前i-1件物品相关的问题。

  • 如果不放第i件物品,问题变为前i-1件物品放入容量为v的背包中,价值为F[i-1,v];
  • 如果放第i件物品,问题就转化为前i-1件物品放入容量为v-w[i]的背包中,价值为F[i-1,v-w[i]]+p[i];

问题:有编号分别为a,b,c,d,e的五件物品,它们的重量分别是2,2,6,5,4,它们的价值分别是6,3,5,4,6,每件物品数量只有一个,现在给你个承重为10的背包,如何让背包里装入的物品具有最大的价值总和?

思路1:建立二维数组 dp[][]。

IDweightprice012345678910
a2600666666666
b2300669999999
c6500669999111114
d54006699910111314
e460066991212151515
public class 背包问题 {
	//w:重量      p:价值
	public static int maxPrice(int V,int[] w,int[] p){
		int[][] dp=new int[w.length][V+1];
		for(int i=0;i<w.length;i++){
			dp[i][0]=0;
		}
		for(int j=1;j<V+1;j++){
			if(w[0]>j){
				dp[0][j]=0;
			}else{
				dp[0][j]=p[0];
			}
			for(int i=1;i<w.length;i++){
				if(w[i]>j){ //放不进去
					dp[i][j]=dp[i-1][j];
				}else{ //放进去
					dp[i][j]=Math.max(dp[i-1][j], dp[i-1][j-w[i]]+p[i]);
				}
			}
		}
		return dp[w.length-1][V];
	}
	public static void main(String[] args){
		int V=10;
		int[] w={2,2,6,5,4};
		int[] p={6,3,5,4,6};
		int max=maxPrice(V, w, p);
		System.out.println(max);
	}
}

思路2:把二维数组变为一维数组。

2.完全背包问题

问题描述:有编号分别为a,b,c,d的四件物品,它们的重量分别是2,3,4,7,它们的价值分别是1,3,5,9,每件物品数量无限个,现在给你个承重为10的背包,如何让背包里装入的物品具有最大的价值总和?

思路:完全背包问题和01背包问题的区别在于每一件物品的数量都有无限个,而01背包每件物品数量只有一个。初始化时,当只考虑一件物品a时,F[1][j]=j/w[a]。递推公式计算时,F[i][y]=max{F[i-1][y],F[i][y-w[i]]+p[i]},注意这里当考虑放入一个物品i时应当考虑还可能继续放入i,因此是F[i][y]=max{F[i-1][y],F[i][y-w[i]]+p[i]},而不是F[i][y]=max{F[i-1][y],F[i-1][y-w[i]]+p[i]}。

public class 完全背包问题 {
	public static int maxPrice(int V,int[] w,int[] p){
		int max=0;
		int[][] dp=new int[w.length][V+1];
		for(int i=0;i<w.length;i++){
			dp[i][0]=0;
		}
		for(int i=1;i<V+1;i++){
			if(w[0]>V){ //放不下
				dp[0][i]=0;
			}else{
				dp[0][i]=p[0];
			}
			for(int j=1;j<w.length;j++){
				if(w[j]>i){
					dp[j][i]=dp[j-1][i];
				}else{
					dp[j][i]=Math.max(dp[j-1][i], dp[j][i-w[j]]+p[j]);
				}
			}
		}
		
		for(int i=0;i<dp.length;i++){
			for(int j=0;j<dp[0].length;j++){
				System.out.print(dp[i][j]+"  ");
			}
			System.out.println();
		}
		return dp[w.length-1][V];
	}
	
	public static void main(String[] args){
		int V=10;
		int[] w={2,3,4,7};
		int[] p={1,3,5,9};
		int res=maxPrice(V, w, p);
		System.out.println(res);
	}

}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值