多重背包(java实现)

多重背包

问题描述

有N件物品,每件物品的重量为weight[ i ],价值为value[ i ]。现有一个容量为W的背包,问如何选取物品放入背包,使得背包内物品的总价值最大。第 i 个物品可以放count[ i ]次。

分析

两种解决办法
1,将同一物品复制n[ i ]份,转换成01背包
2,将count[ i ]拆分为1 2 4 8 … 2 ^ (k-1) , count[ i ]-2^k ,这些数存在倍数关系,可以很方便推算。例如:13=1+2+4+6

状态转移方程
sum[ i ][ j ]=max{sum[ i-1 ][ j-k * weight[ i ] ]+k*value[ i ] | 0<=k<=count[ i ] }

只要把01背包理解了,这个还是很简单的

代码

public class BackPack02 {
	//多重背包
	
	static int N=4;//物品有3件
	static int W=9;//背包容量为8
	static int weight[]= {0,1,2,2};//物品重量1 2 2
	static int value[]= {0,6,10,20};//物品价值6 10 20
	static int count[] = {0,10,5,2};//物品数量10 5 2
	static int sum[];
	
	public static void getValue(int i) {//完全背包
		for(int j=1;j<W;j++) {
			if(weight[i]<=j) {
				sum[j]=Math.max(sum[j], sum[j-weight[i]]+value[i]);
			}
		}	
	}
	
	public static void getValue1(int i,int k) {//01背包
		for(int j=W-1;j>=1;j--) {
			if(k*weight[i]<=j) {
				sum[j]=Math.max(sum[j], sum[j-k*weight[i]]+k*value[i]);
			}
		}
	}
	
	public static void getValue2() {//多重背包
		for(int i=1;i<N;i++) {//遍历 i 件物品
			int temp=count[i];//记录第i件物品可选数量
			
			if(count[i]*weight[i]>=W) {//第i件物品总重量超过背包容量,转换为完全背包
				getValue(i);
			}else {//01背包
				int k=1;
				while(k<temp) {
					getValue1(i,k);//k:选择 k 件物品 i 
					count[i]=count[i]-k;
					k=k*2;
				}
				getValue1(i,count[i]);
			}	
		}
		
		System.out.println(sum[8]);
	}
	
	public static void main(String[] args) {
		sum=new int[W];
		
		getValue2();
	}
}

输出

64

你可能感兴趣的:(算法)