Skip to content

Commit e615242

Browse files
committed
add LDS Solver
1 parent e1a6978 commit e615242

File tree

1 file changed

+151
-19
lines changed

1 file changed

+151
-19
lines changed

discrete-optimization/knapsack/Solver.java

Lines changed: 151 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
1-
import java.io.*;
2-
import java.util.List;
3-
4-
1+
import java.io.BufferedReader;
2+
import java.io.FileReader;
3+
import java.io.IOException;
54
import java.util.ArrayList;
5+
import java.util.Arrays;
6+
import java.util.HashMap;
7+
import java.util.List;
8+
import java.util.Map;
69

710
/**
8-
* The class <code>Solver</code> is an implementation of a greedy algorithm to solve the knapsack problem.
11+
* The class <code>Solver</code> is an implementation of solve framework to solve the knapsack problem.
912
*
1013
*/
1114
public class Solver {
@@ -67,36 +70,93 @@ public static void solve(String[] args) throws IOException {
6770
weights[i-1] = Integer.parseInt(parts[1]);
6871
}
6972

73+
Item[] a = new Item[items];
74+
for(int i=0 ; i<items ; ++i){
75+
a[i] = new Item();
76+
a[i].value = values[i];
77+
a[i].weight = weights[i];
78+
a[i].idx = i;
79+
}
80+
Arrays.sort(a);
81+
// for(int i=0 ; i< items ; ++i)
82+
// System.out.println(a[i].value + " " + a[i].weight);
83+
for(int i=0 ; i<items ; ++i){
84+
values[i] = a[i].value;
85+
weights[i] = a[i].weight;
86+
}
7087
// a trivial greedy algorithm for filling the knapsack
7188
// it takes items in-order until the knapsack is full
7289

73-
KnapsackSolver solver = new DPSolver();
74-
solver.solve(items,capacity,values,weights);
75-
90+
// KnapsackSolver solver = (long) items*capacity > DPSolver.MAX_SOLVE_SPACE?
91+
// new LDSSolver() : new DPSolver();
92+
93+
KnapsackSolver solver = new LDSSolver();
94+
95+
Map<String,Object> ans = solver.solve(items,capacity,values,weights);
96+
int[] taken = new int[items];
97+
int[] ansIdx = (int[])ans.get("taken");
98+
for(int i=0 ; i<items ; ++i)taken[a[i].idx] = ansIdx[i];
99+
ans.put("taken", taken);
100+
output(ans);
76101
}
77-
public static void output(int value,int opt,int[] taken) {
102+
public static void output(Map<String,Object> ans) {
103+
int value = (int)ans.get("value");
104+
int opt = (int)ans.get("opt");
105+
int[] taken = (int[])ans.get("taken");
78106
System.out.println(value+" "+opt);
79107
int items = taken.length;
80108
for(int i=0; i < items; i++){
81109
System.out.print(taken[i]+" ");
82110
}
83111
System.out.println("");
84112
}
113+
public static Map<String,Object> constructAns(int value,int opt,int[] taken) {
114+
Map<String,Object> ans = new HashMap<>();
115+
ans.put("value", value);
116+
ans.put("opt", opt);
117+
ans.put("taken", taken);
118+
119+
return ans;
120+
}
121+
122+
123+
}
124+
125+
/**
126+
* Item
127+
*/
128+
class Item implements Comparable<Item>{
129+
int value,weight;
130+
int idx;
131+
public int compareTo(Item o){
132+
return value - o.value;
133+
}
85134
}
86135

87136

137+
/**
138+
* This interface <code> KnapsackSolver </code> provides a general interface for solving knapsack problem
139+
*/
88140
interface KnapsackSolver{
89-
public void solve(int n,int K,int[] values,int[] weights);
141+
/**
142+
* this method is a interface that given items {@code n}, capcity {@code K}, and value {@code values} with {@code weights}
143+
* @param n number of items
144+
* @param K capcity of bag
145+
* @param values a int array {@code values[i]} represented the value of ith item
146+
* @param weights a int array {@code weights[i]} represented the weight of ith item
147+
*/
148+
public Map<String,Object> solve(int n,int K,int[] values,int[] weights);
90149
}
91150

151+
/**
152+
* this a danamic programing solver for knapsack problem
153+
*/
154+
92155
class DPSolver implements KnapsackSolver{
93-
private static final int MAX_SOLVE_SPACE = 100000000;
94-
public void solve(int n,int K,int[] values,int[] weights){
95-
if(n * K > MAX_SOLVE_SPACE)
96-
System.err.printf("need memory %d, but MAX_SOLVE_SPACE is %d\n",n*K,MAX_SOLVE_SPACE);
156+
public static final int MAX_SOLVE_SPACE = 100000000;
157+
public Map<String,Object> solve(int n,int K,int[] values,int[] weights){
97158
int maxv;
98-
int opt =1;
99-
int[] token = new int[n];
159+
int[] taken = new int[n];
100160
int[][] dp = new int[K+1][n];
101161
for(int k = 1 ; k <= K ; ++k){
102162
dp[k][0] = (k >=weights[0]? values[0] : 0);
@@ -111,11 +171,83 @@ public void solve(int n,int K,int[] values,int[] weights){
111171
int k = K;
112172
for(int j = n-1 ; j >0 ; --j ){
113173
if(k >= weights[j] && dp[k][j] == dp[k-weights[j]][j-1] +values[j]){
114-
token[j] =1;
174+
taken[j] =1;
115175
k -=weights[j];
116176
}
117177
}
118-
if(dp[k][0] !=0)token[0] =1;
119-
Solver.output(maxv, opt, token);
178+
if(dp[k][0] !=0)taken[0] =1;
179+
return Solver.constructAns(maxv, 1, taken);
120180
}
121181
}
182+
183+
/**
184+
* LDSSolver,limited discrepancy search solver for knapsack problem
185+
*/
186+
class LDSSolver implements KnapsackSolver{
187+
188+
/**
189+
* just for least paras in member methods
190+
*/
191+
private int[] vals;
192+
private int[] weights;
193+
private int ans;
194+
private int[] bestVec; // the final tacken vector
195+
private static final long elapsedTime = 1000000000L;//10 s
196+
private long startTime;
197+
public Map<String,Object> solve(int n,int K,int[] v,int [] w) {
198+
vals = v;
199+
weights = w;
200+
KnapsackSolver initSolver = new DPSolver();
201+
int cap = Math.min(DPSolver.MAX_SOLVE_SPACE/n,K);
202+
Map<String,Object> initAns = initSolver.solve(n, cap, v, w);
203+
if((long)n*K <= DPSolver.MAX_SOLVE_SPACE) return initAns;
204+
ans = (int)initAns.get("value");
205+
// System.out.println("dp ans= " + ans);
206+
bestVec = (int[])initAns.get("taken");
207+
int tks = 0;
208+
for(int i=0 ; i < n ; ++i)tks += bestVec[i];
209+
210+
211+
int[] tmpw = weights.clone();
212+
Arrays.sort(tmpw);
213+
int min = 0;
214+
int s =0;
215+
for( ; s+weights[min] <= K && min <n ; s+= weights[min],min++ );
216+
for(int i=min ; i < n ; ++i)s+=weights[i];
217+
for(int mis = n-min; mis <=n-tks+5; ++mis){
218+
startTime = System.nanoTime();
219+
lds(0, s,K,mis, n-1, new int[n]);
220+
}
221+
222+
return Solver.constructAns(ans, 0, bestVec);
223+
}
224+
/**
225+
* ths limited discrepancy search method, you can find detail at this paper {@link https://ai.dmi.unibas.ch/research/reading_group/harvey-ginsberg-ijcai1995.pdf}
226+
* @param best the value of cur node
227+
* @param estimate the best value of cur node
228+
* @param leftCap the left capcity
229+
* @param mistake the right branch of search tree
230+
* @param i the ith item
231+
* @return
232+
*/
233+
private void lds(int best,int estimate,int leftCap,int mistake,int i,int[] taken) {
234+
if(estimate < ans) return;// prun the branch
235+
if(mistake >i+1)return;
236+
if(leftCap <0)return;
237+
if(i < 0 || leftCap-weights[i]<0|| System.nanoTime() - startTime > elapsedTime){
238+
if(best > ans){
239+
ans = best;
240+
for(int j=taken.length-1 ; j >i ; --j)bestVec[j] = taken[j];
241+
for(int j=i ; j>=0 ; --j)bestVec[j] =0;
242+
}
243+
return;
244+
}
245+
// not take the ith item, mistake -1
246+
if(mistake>0){
247+
taken[i] =0;
248+
lds(best, estimate, leftCap, mistake-1, i-1, taken);
249+
}
250+
taken[i] =1;
251+
lds(best + vals[i], estimate - vals[i],leftCap-weights[i], mistake, i-1, taken);
252+
}
253+
}

0 commit comments

Comments
 (0)