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 }