第七周作业1——背包问题

作业要求: 对数据文件Knapsack.txt (第一行为背包总重量15,物品数量5;第2-6行,分别为第1-5件物品的重量与价值,W=15) , 编程计算最终背包所装物品的编号、总重量与总价值。要求能够把构造的二维表格输出到文件KnapsackResult.txt中。

数据文件内容:


单副本的背包问题(Knapsack without repetition):N件物品,分别重w1,...,wn,价值为v1,...,vn,现有一个背包最大容量为W,怎样的组合才能够使背包中装下的物品价值最高?

摘自:    knapsack-problem(http://www.answers.com/topic/knapsack-problem)

单副本背包问题的伪代码:



用Java实现单副本背包问题,代码如下:

/**
 * 单副本背包问题
 */
public class Knapsack {
	
	/**
	 * 计算背包问题的二维表格
	 * @param W 背包可容纳的最大重量
	 * @param n 物品数量
	 * @param K 二维表格
	 * @param wv wv[i][0]=w(该物品的重量) , wv[i][1]=v(该物品的价值) , 0<=i<=n
	 */
	public int[][] getArray(int W, int n, int wv[][]){
		//第一行和第一列的所有值为0
		int[][] K = new int[W+1][n+1];
		
		//核心代码的实现,参照伪代码
		for(int j=1; j<=n; j++){
			for(int w=1; w<=W; w++){
				int maxW = wv[j-1][0];
				if(maxW>w){
					K[w][j] = K[w][j-1];
				}else{
					K[w][j] = max(K[w][j - 1],K[w - maxW][j - 1]+wv[j - 1][1]);
				}
			}
		}
		return K;
	}
	
	public int max(int a, int b){
		return a>b ? a : b;
	}
	
	/**
	 * 计算放入背包中的物品总质量和哪些物品放到背包中
	 * @param wv wv[i][0]=w(该物品的重量) , wv[i][1]=v(该物品的价值) , 0<=i<=n
	 * @param K 存储背包问题的二维数组
	 * @param W 背包可容纳的最大重量
	 * @param n 物品数量
	 * @return isTaked[] 第一个位置放
	 */
	public static int[] getIsTaked(int[][] wv,int[][] K,int W,int n){
		/* 下标为0的数组值存储放到背包里的物品总价值
		从下标1开始记录该物品编号是否放入背包中(下标即为物品的编号),
		1是放入,0是不放入 */
		int isTaked[]=new int[n+1];
		
		int w = W;		
		for(int j=n;j>0;j--){
			if(K[w][j]>K[w][j-1]){
				isTaked[j]=1;
				w = w - wv[j-1][0];
				if(w<0) break;
			}
		}		
		
		//计算放入背包的物品总重量
		int sumW=0;
		for(int j=1;j<=n;j++){
			if(isTaked[j]==1){
				sumW+=wv[j-1][0];
			}
		}
		isTaked[0] = sumW;
		
		return isTaked;
	}
	
}

测试代码:

	public static void main(String[] args) throws IOException  {
		Scanner scanner = new Scanner(Knapsack.class.getResourceAsStream("Knapsack.txt"));	
		Writer out = new FileWriter(new File("src/KnapsackResult.txt"));		
		
		//第一行为背包总重量15,物品数量5
		int W=scanner.nextInt(), n=scanner.nextInt();
		//将每个物品的重量和价值保存到数组wv
		int wv[][] = new int[n][2];
		for(int i=0; i<n; i++){
			wv[i][0]=scanner.nextInt();
			wv[i][1]=scanner.nextInt();
		}
		
		Knapsack knapsack = new Knapsack();
		int K[][] = knapsack.getArray(W, n, wv);			
		
		//将背包问题的二维表格保存到问文件KnapsackResult.txt
		for(int w=0; w<=W; w++){
			for(int j=0; j<=n; j++){
				out.write(K[w][j]+"\t");
			}
			out.write("\r\n");
		}
		out.close();
		scanner.close();
		
		int[] isTaked = getIsTaked(wv, K, W, n);
		System.err.println("放入背包中的物品总重量为: "+isTaked[0]);
		
		System.err.println("放入背包中的物品编号为: ");
		for(int No=1; No<isTaked.length; No++){
			if(isTaked[No] == 1) System.err.print(No + "\t");
		}
		 
	}


测试结果:




利用动态规划原理进行求解 0-1背包问题 已知背包的容量为b,有n种物件,其价格依次为w1,w2,...,wn;其容量依次为v1,v2,...,vn。 现要求在背包允许的容量内,装的物件价值达到最大,其数字模型为: max z=1 x1 + 6 x2 + 18 x3 + 22 x4 + 28 x5 1 x1 + 2 x2 + 5 x3 + 6 x4 + 7 x5 <=11 xi=0,1 i=1,2,3,4,5 S(i,j)=max{S(i-1,j),S(i-1,j-vi)+wi} S(0,j)=0 j>=0 S(i,j)=负无穷 j<0 i=1,w1=1,v1=1 S(1,1)=max{S(0,1),S(0,1-1)+1}=1 S(1,2)=max{S(0,2),S(0,2-1)+1}=1 S(1,3)=...=S(1,11)=1 i=2,w2=6,v2=2 S(2,1)=max{S(1,1),S(1,1-2)+6}=1 S(2,2)=max{S(1,1),S(1,2-2)+6}=6 S(2,3)=max{S(1,3),S(1,3-2)+6}=7 S(2,4)=...=S(2,11)=7 i=3,w3=18,v3=5 S(3,1)=max{S(2,1),S(2,1-5)+18}=1 S(3,2)=max{S(2,2),S(2,2-5)+18}=6 S(3,3)=max{S(2,3),S(2,3-5)+18}=7 S(3,4)=max{S(2,4),S(2,4-5)+18}=7 S(3,5)=max{S(2,5),S(2,5-5)+18}=18 S(3,6)=max{S(2,6),S(2,6-5)+18}=19 S(3,7)=max{S(2,7),S(2,7-5)+18}=24 S(3,8)=max{S(2,8),S(2,8-5)+18}=25 S(3,9)=S(3,10)=...=S(3,11)=25 i=4,w4=22,v4=6 S(4,1)=max{S(3,1),S(3,1-6)+22}=1 S(4,2)=max{S(3,2),S(3,2-6)+22}=6 S(4,3)=max{S(3,3),S(3,3-6)+22}=7 S(4,4)=max{S(3,4),S(3,4-6)+22}=7 S(4,5)=max{S(3,5),S(3,5-6)+22}=18 S(4,6)=max{S(3,6),S(3,6-6)+22}=22 S(4,7)=max{S(3,7),S(3,7-6)+22}=24 S(4,8)=max{S(3,7),S(3,8-6)+22}=38 S(4,9)=max{S(3,7),S(3,9-6)+22}=29 S(4,10)=max{S(3,7),S(3,10-6)+22}=29 S(4,11)=max{S(3,7),S(3,11-6)+22}=40 i=5,w5=28,v5=7 S(5,1)=max{S(4,1),S(4,1-7)+28}=1 S(5,2)=max{S(4,2),S(4,2-7)+28}=6 S(5,3)=max{S(4,3),S(4,3-7)+28}=7 S(5,4)=max{S(4,4),S(4,4-7)+28}=7 S(5,5)=max{S(4,5),S(4,5-7)+28}=18 S(5,6)=max{S(4,6),S(4,6-7)+28}=22 S(5,7)=max{S(4,7),S(4,7-7)+28}=28 S(5,8)=max{S(4,8),S(4,8-7)+28}=29 S(5,9)=max{S(4,9),S(4,9-7)+28}=34 S(5,10)=max{S(4,10),S(4,10-7)+28}=35 S(5,11)=max{S(4,11),S(4,11-7)+28}=40
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值