package com.duoduo.day316; /** * 0-1背包问题 * * 问题描述:有n个物品,每个物品的重量为w[i], 价值为v[i],购物车容量为W,选择若干个物品放入购物车 * 限制:在不超过容量的前提下使获得的价值最大 * 思路:和之前的贪心算法(背包问题)不同,故分析最优子结构后,采用动态规划思想求解 * * c[i][j]: 前i件物品放入一个容量为j的购物车可以获得的最大价值 * 购物车容量不足,肯定不能放入: * c[i][j]= c[i-1][j] j<wi * 购物车容量足,看放入,不放入哪种情况获得的价值最大: * c[i][j]= max{c[i-1][j],c[i-1][j-w[i]]+v[i] j>=wi * * @author 多多 * */ import java.util.Scanner; public class Test4_9 { public static void main(String [] args) { Scanner sc=new Scanner(System.in); System.out.println("请输入物品的个数n:"); int n=sc.nextInt(); //物品的个数 System.out.println("请输入购物车的容量:"); int W=sc.nextInt(); System.out.println("请依次输入每个物品的重量 w 和价值 v,用空格分开:"); int [] w=new int[n+1]; //每个物品的重量 int [] v=new int[n+1]; //每个物品的价值 for(int i=1;i<=n;i++) { //存入键入的数据 w[i]=sc.nextInt(); v[i]=sc.nextInt(); } int [][] c=new int[n+1][W+1]; //c[i][j] : 前i件物品放入一个容量为j的购物车可以获得的最大价值 //初始化数组 c[i][j] for(int i=0;i<=n;i++) c[i][0]=0; for(int j=0;j<=W;j++) c[0][j]=0; /*计算c[i][j]的递归式 购物车容量不足,肯定不能放入: c[i][j]= c[i-1][j] j<wi 购物车容量足,看放入,不放入哪种情况获得的价值最大: c[i][j]= max{c[i-1][j],c[i-1][j-w[i]]+v[i] j>=wi */ for(int i=1;i<=n;i++) { for(int j=1;j<=W;j++) { if(j<w[i]) { c[i][j]=c[i-1][j]; //购物车容量不足,肯定不能放入: }else { c[i][j]=max(c[i-1][j],c[i-1][j-w[i]]+v[i]);//购物车容量足,看放入,不放入哪种情况获得的价值最大: } } } System.out.println("装入购物车的最大价值:"+c[n][W]); /*逆向构造最优解 * 根据c[i][j]数组的计算结果 逆向 逆推 用一个一维数组x[]记录解向量 * x[i]=1 表示第i个物品放入购物车 * x[i]=0 表示不放入购物车 * */ int [] x=new int[n+1]; int j=W; for(int i=n;i>0;i--) { if(c[i][j]>c[i-1][j]) { //说明第i个物品放入购物车 标记为1 且 购物车容量--物品重量 x[i]=1; j-=w[i]; }else { x[i]=0; //否则 未放入 则标记为0 } } System.out.println("装入购物车的物品为:"); for(int i=1;i<=n;i++) { if(x[i]==1) System.out.print(i+" "); //打印标记为1 的物品 } } private static int max(int i, int j) { return i>j? i:j ; } }
结果:
时间复杂度:主要是两层嵌套 O(n*W)
空间复杂度:c[n][W] O(n*W)