再谈01背包 | 使用【跳跃点集合】代替【求解矩阵】解题
上文链接:9大背包第一弹 | 01背包
输入:
1 double []w={2,2,6,5,4}; 2 double []v={6,3,5,4,6}; 3 double weight=10; 4 _01package problem=new _01package(w,v,weight);
输出:
1 应该放入背包的物品:5 2 1
【跳跃点集合】Java代码:
1 class _01package{ 2 //价值、重量 3 int [][] matrix; 4 List<Integer> solve=new ArrayList<Integer>(); 5 //使用跳跃点集合解题 6 _01package(double [] w,double [] v,double weight){ 7 int len=w.length; 8 class struct{ //新建一个二元组,表示当背包容量为w时,背包的价值为v 9 double w=0; 10 double v=0; 11 struct(){} 12 struct(double w,double v){this.w=w;this.v=v;} 13 } 14 List<struct> p[]=new ArrayList[len+1];//表示全部的跳跃点 C[i][j] 15 List<struct> q[]=new ArrayList[len+1];//表示跳跃点 C[i][j-wi]+vi 16 double[] W=new double[len+1]; 17 double[] V=new double[len+1]; 18 W[0]=0; 19 V[0]=0; 20 int i,j,k; 21 for(i=1;i<=len;i++) W[i]=w[i-1]; 22 for(i=1;i<=len;i++) V[i]=v[i-1]; 23 p[0]=new ArrayList<struct>(); 24 p[0].add(new struct(0,0));//初始变量 25 for(i=1;i<=len;i++){//依次放入物品 26 //q[i-1]=p[i-1]⊕(wi,vi) 解得q,跳跃点C[i][j-wi]+vi 27 q[i-1]=new ArrayList<struct>(); 28 for(j=0;j<p[i-1].size();j++){ 29 struct tmp=new struct(p[i-1].get(j).w+W[i],p[i-1].get(j).v+V[i]); 30 31 q[i-1].add(tmp); 32 } 33 //p[i]=p[i-1]∪q[i-1] 取并集 34 p[i]=new ArrayList<struct>(); 35 p[i].addAll(p[i-1]); 36 p[i].addAll(q[i-1]); 37 int b; 38 b=0; 39 //按照w对p进行重排序 40 int pLen=p[i].size(); 41 for(j=1;j<pLen;j++) //冒泡排序 42 for(k=0;k<pLen-j;k++) 43 if(p[i].get(k).w>p[i].get(k+1).w){//应交换 44 struct tmp_p=p[i].get(k); 45 struct tmp=new struct(tmp_p.w,tmp_p.v); 46 p[i].set(k, p[i].get(k+1)); 47 p[i].set(k+1, tmp); 48 } 49 50 //对p执行检查操作,查看是否有【超限】和【不满足递增】的情况 51 double preV=0; 52 for(j=0;j<p[i].size();){ 53 if(p[i].get(j).w>weight //【超限】 54 || p[i].get(j).v<preV ){//【不满足递增】 55 56 p[i].remove(j);//删除j元素 57 }else{ 58 preV=p[i].get(j).v; 59 j++; 60 61 } 62 } 63 } 64 //对p进行回溯 65 int t=p[len].size()-1;// 66 double wx=p[len].get(t).w;//wx:初始化为最大重量 67 double vx=p[len].get(t).v;//wv:初始化为最大价值 68 for(j=len;j>0;j--){// 69 for(k=0;k<p[j].size();k++){ 70 double tw=p[j].get(k).w; 71 double tv=p[j].get(k).v; 72 if(tw+W[j]==wx && tv+V[j]==vx){ 73 wx=tw; 74 vx=tv; 75 solve.add(j); 76 } 77 } 78 } 79 System.out.print("应该放入背包的物品:"); 80 for(i=0;i<solve.size();i++) System.out.print(solve.get(i)+" "); 81 System.out.println(); 82 }
完整代码:
1 import java.util.*; 2 3 public class Main { 4 5 public static void main(String[] args) { 6 // TODO Auto-generated method stub 7 double []w={2,2,6,5,4}; 8 double []v={6,3,5,4,6}; 9 double weight=10; 10 _01package problem=new _01package(w,v,weight); 11 12 13 } 14 15 } 16 17 class _01package{ 18 //价值、重量 19 int [][] matrix; 20 List<Integer> solve=new ArrayList<Integer>(); 21 //使用跳跃点集合解题 22 _01package(double [] w,double [] v,double weight){ 23 int len=w.length; 24 class struct{ //新建一个二元组,表示当背包容量为w时,背包的价值为v 25 double w=0; 26 double v=0; 27 struct(){} 28 struct(double w,double v){this.w=w;this.v=v;} 29 } 30 List<struct> p[]=new ArrayList[len+1];//表示全部的跳跃点 C[i][j] 31 List<struct> q[]=new ArrayList[len+1];//表示跳跃点 C[i][j-wi]+vi 32 double[] W=new double[len+1]; 33 double[] V=new double[len+1]; 34 W[0]=0; 35 V[0]=0; 36 int i,j,k; 37 for(i=1;i<=len;i++) W[i]=w[i-1]; 38 for(i=1;i<=len;i++) V[i]=v[i-1]; 39 p[0]=new ArrayList<struct>(); 40 p[0].add(new struct(0,0));//初始变量 41 for(i=1;i<=len;i++){//依次放入物品 42 //q[i-1]=p[i-1]⊕(wi,vi) 解得q,跳跃点C[i][j-wi]+vi 43 q[i-1]=new ArrayList<struct>(); 44 for(j=0;j<p[i-1].size();j++){ 45 struct tmp=new struct(p[i-1].get(j).w+W[i],p[i-1].get(j).v+V[i]); 46 47 q[i-1].add(tmp); 48 } 49 //p[i]=p[i-1]∪q[i-1] 取并集 50 p[i]=new ArrayList<struct>(); 51 p[i].addAll(p[i-1]); 52 p[i].addAll(q[i-1]); 53 int b; 54 b=0; 55 //按照w对p进行重排序 56 int pLen=p[i].size(); 57 for(j=1;j<pLen;j++) //冒泡排序 58 for(k=0;k<pLen-j;k++) 59 if(p[i].get(k).w>p[i].get(k+1).w){//应交换 60 struct tmp_p=p[i].get(k); 61 struct tmp=new struct(tmp_p.w,tmp_p.v); 62 p[i].set(k, p[i].get(k+1)); 63 p[i].set(k+1, tmp); 64 } 65 66 //对p执行检查操作,查看是否有【超限】和【不满足递增】的情况 67 double preV=0; 68 for(j=0;j<p[i].size();){ 69 if(p[i].get(j).w>weight //【超限】 70 || p[i].get(j).v<preV ){//【不满足递增】 71 72 p[i].remove(j);//删除j元素 73 }else{ 74 preV=p[i].get(j).v; 75 j++; 76 77 } 78 } 79 } 80 //对p进行回溯 81 int t=p[len].size()-1;// 82 double wx=p[len].get(t).w;//wx:初始化为最大重量 83 double vx=p[len].get(t).v;//wv:初始化为最大价值 84 for(j=len;j>0;j--){// 85 for(k=0;k<p[j].size();k++){ 86 double tw=p[j].get(k).w; 87 double tv=p[j].get(k).v; 88 if(tw+W[j]==wx && tv+V[j]==vx){ 89 wx=tw; 90 vx=tv; 91 solve.add(j); 92 } 93 } 94 } 95 System.out.print("应该放入背包的物品:"); 96 for(i=0;i<solve.size();i++) System.out.print(solve.get(i)+" "); 97 System.out.println(); 98 } 99 100 //使用求解矩阵进行求解 101 _01package(int [] w,int [] v,int weight){ 102 int i,j; 103 int len=w.length; 104 matrix=new int[len+1][weight+1];//构建求解数组 105 for(i=0;i<weight+1;i++) matrix[0][i]=0;//第一行为0 106 for(i=0;i<len+1;i++) matrix[i][0]=0;//第一列为0 107 //动态规划 108 for(i=1;i<len+1;i++){ //从上到下【不断将物品放入背包】【i】代表物品 109 for(j=1;j<weight+1;j++){ //从左到右【背包的容量不断扩充】【j】代表当前容量 110 if(j>w[i-1]){//【当前背包容量】比【将要放入的物品】的【重量】大 111 matrix[i][j]=Math.max 112 (matrix[i-1][j], //选择不放 113 matrix[i-1][j-w[i-1]]+v[i-1]); //让背包腾出w[i-1],即【当前物品】的【重量】的空间,选择放入 114 }else{ //放不进。拷贝【上一个物品】的重量 115 matrix[i][j]=matrix[i-1][j]; 116 } 117 } 118 } 119 System.out.println("求解矩阵:"); 120 System.out.print(this); 121 //回溯 122 j=weight;//最后一列 123 for(i=len;i>0;i--){//对行进行遍历 124 if(matrix[i][j]>matrix[i-1][j]){//增减物品时,价值增加了。说明放入了物品 125 j-=w[i-1]; 126 solve.add(i); 127 } 128 } 129 System.out.print("应该放入背包的物品:"); 130 for(i=0;i<solve.size();i++) System.out.print(solve.get(i)+" "); 131 System.out.println(); 132 } 133 134 public String toString(){ 135 int row = matrix.length;//行数 136 int col =matrix[0].length;//列数 137 String str=new String(""); 138 int i,j; 139 for(i=0;i<row;i++){ 140 for(j=0;j<col;j++){ 141 str+=Integer.toString(matrix[i][j]); 142 str+="\t"; 143 } 144 str+="\n\n"; 145 } 146 return str; 147 } 148 }