回溯法~0-1背包的实现
1 package 背包; 2 3 4 import java.util.ArrayList; 5 import java.util.Collections; 6 import java.util.Comparator; 7 import java.util.HashMap; 8 import java.util.Map; 9 import java.util.Scanner; 10 11 public class 背包 { 12 /* 13 * 非递归回溯********************************** 14 * 1.单位性价比,按高到第放入。 15 * 2.需要变量~固有变量 ~背包容量,物品大小,物品价值, (物品大小数组,物品价值数组) 16 * 3.需要变量~判断变量~当前背包容量,当前背包价值,当前最优价值,剩余价值(性价比) 17 * 4.根据性价比排列物品,降序排序物品。 18 * 5.hashmap 用于确定物品id。并用于排序 19 * 6.输出放入的物品时,应将id转化为原数组位置。 20 * */ 21 static double c; //背包容量 22 static int n; //物品数量 23 static double []p;// 物品价值 24 static double []p1;// 重新排列的 物品价值 25 static double []w;//物品大小 26 static double []w1;//重新排列的物品大小 27 static double cw; //当前容量 28 static double cp; //当前价值 29 static double bestp;//当前最优解 30 static double []q; //性价比 31 static double sp; //物品剩余价值 32 static int[]x; //x[0:i-1]为当前路径 33 static int[]bestx;//当前最优路径 34 public static void main(String[] args) { 35 36 37 Scanner sc = new Scanner(System.in); 38 39 System.out.println("背包容量"); 40 c=sc.nextInt(); 41 System.out.println("物品数量"); 42 n=sc.nextInt(); 43 double w[]=new double[n]; 44 double p[]=new double[n]; 45 46 //初始化其他变量 47 bestp=0; 48 cw=0; 49 cp=0; 50 51 52 53 System.out.println("物品大小"); 54 for(int i = 0 ; i<n;i++) 55 { 56 w[i]=sc.nextDouble(); 57 } 58 System.out.println("物品价值"); 59 { 60 for(int i = 0 ; i<n;i++) 61 { 62 p[i]=sc.nextDouble(); 63 64 } 65 } 66 //初始化剩余价值 67 for(int i =0;i<n;i++) 68 { 69 sp+=p[i]; 70 } 71 72 sc.close(); 73 74 xjb(p,w,n); 75 76 77 78 79 } 80 81 //初始化,判断性价比,按降序排列 82 @SuppressWarnings("unchecked") 83 public static void xjb (double []p,double[]w,int n) 84 { 85 //初始化 ,并降序排序,获得物品的id排序(用来判断物品的优先放入) 86 double []q =new double[n]; 87 88 for(int i = 0 ; i<n;i++) 89 { 90 q[i]=p[i]/w[i]; 91 } 92 93 final Map<Integer,Double> map = new HashMap<Integer,Double>(); 94 for(int i = 0;i<n;i++) 95 { 96 map.put(i,q[i]); 97 } 98 @SuppressWarnings("rawtypes") 99 ArrayList keys = new ArrayList(map.keySet());//得到key集合 100 101 //把keys排序,但是呢,要按照后面这个比较的规则 102 Collections.sort(keys,new Comparator<Object>(){ 103 104 public int compare(Object o1,Object o2){ 105 106 //按照value的值降序排列,若要升序,则这里小于号换成大于号 107 if(Double.parseDouble(map.get(o1).toString())<Double.parseDouble(map.get(o2).toString())) 108 return 1; 109 110 else if(Double.parseDouble(map.get(o1).toString())==Double.parseDouble(map.get(o2).toString())) 111 return 0; 112 113 else 114 return -1; 115 } 116 } 117 ); 118 System.out.println("***按照性价比排列物品,由大到小排列***"+keys); 119 120 121 double w1[]=new double[n]; 122 double p1[]=new double[n]; 123 //根绝性价比重新排列物品大小数组。 124 for(int j =0;j<n;j++) 125 { 126 127 w1[j]=w[(Integer) keys.get(j)]; 128 } 129 130 //根绝性价比重新排列物品价值数组 131 for(int j =0;j<n;j++) 132 { 133 p1[j]=p[(Integer) keys.get(j)]; 134 } 135 System.out.println(beibao01(w1,p1,keys)); 136 137 } 138 139 140 @SuppressWarnings("rawtypes") 141 public static double beibao01(double[]w1,double[]p1,ArrayList keys ) 142 { 143 144 int i =0; 145 int[]x=new int[n]; 146 int[]bestx=new int[n]; 147 148 while(true){ 149 150 while(i<n&&cw+w1[i]<=c) 151 {//当前空间+此次空间 <=背包容量 152 153 //进入左子树 154 x[i]=1; 155 cw+=w1[i]; 156 cp+=p1[i]; 157 sp-=p1[i]; 158 i++; 159 160 } 161 if(i==n) //到达叶子节点 ||c==cp 当背包满的时候退出~~ 162 { 163 if(cp>bestp){ // 这里居然写反了...!! 164 for(int j =0;j<n;j++) 165 { 166 bestx[j]=x[j]; 167 168 } 169 bestp = cp; 170 } 171 } 172 else 173 { //既然怒右子树 174 x[i]=0; 175 sp-=w1[i]; 176 i++; 177 178 } 179 180 181 while(cp+sp<=bestp)//当前价值+剩余价值>=当前最优解 182 { 183 i--; 184 185 while(i>=0 && x[i]==0) //返回时,若不是第一层且 上一层没有放入载重品。 186 { 187 //从右子树返回 188 sp+=w1[i]; //剩余载重恢复上一层数据 189 i--; //再次返回更上一层 190 191 } 192 if(i<0) 193 {//若返回至第一层。则,最优解即为bestw。 194 195 196 for(int j =0;j<n;j++) 197 { 198 if(bestx[j]==1) 199 System.out.println("***放入***"+"w["+keys.get(j)+"]"); 200 } 201 return bestp; 202 } 203 204 x[i]=0; 205 cw-=w1[i]; //卸下载重 206 cp-=p1[i]; //减少价值 207 i++; //进入循环, 判断是否 进入左子树 208 209 //进入右子树 ,当返回至 x[i]=1时,既放入载重品,进入右子树,因为左子树已经判断不会有大于当前最优解的方法。 210 211 } 212 213 214 } 215 216 } 217 }