-
Notifications
You must be signed in to change notification settings - Fork 6
/
Copy pathTSP_DP.java
173 lines (153 loc) · 5.61 KB
/
TSP_DP.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
import java.util.*;
/**
* Date 11/17/2015
* @author Tushar Roy
*
* Help Karp method of finding tour of traveling salesman.
*
* Time complexity - O(2^n * n^2)
* Space complexity - O(2^n)
*
* https://en.wikipedia.org/wiki/Held%E2%80%93Karp_algorithm
*/
public class TravelingSalesmanHeldKarp {
private static int INFINITY = 100000000;
private static class Index {
int currentVertex;
Set<Integer> vertexSet;
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Index index = (Index) o;
if (currentVertex != index.currentVertex) return false;
return !(vertexSet != null ? !vertexSet.equals(index.vertexSet) : index.vertexSet != null);
}
@Override
public int hashCode() {
int result = currentVertex;
result = 31 * result + (vertexSet != null ? vertexSet.hashCode() : 0);
return result;
}
private static Index createIndex(int vertex, Set<Integer> vertexSet) {
Index i = new Index();
i.currentVertex = vertex;
i.vertexSet = vertexSet;
return i;
}
}
private static class SetSizeComparator implements Comparator<Set<Integer>>{
@Override
public int compare(Set<Integer> o1, Set<Integer> o2) {
return o1.size() - o2.size();
}
}
public int minCost(int[][] distance) {
//stores intermediate values in map
Map<Index, Integer> minCostDP = new HashMap<>();
Map<Index, Integer> parent = new HashMap<>();
List< Set<Integer> > allSets = generateCombination(distance.length - 1);
for(Set<Integer> set : allSets) {
for(int currentVertex = 1; currentVertex < distance.length; currentVertex++) {
if(set.contains(currentVertex)) {
continue;
}
Index index = Index.createIndex(currentVertex, set);
int minCost = INFINITY;
int minPrevVertex = 0;
//to avoid ConcurrentModificationException copy set into another set while iterating
Set<Integer> copySet = new HashSet<>(set);
for(int prevVertex : set) {
int cost = distance[prevVertex][currentVertex] + getCost(copySet, prevVertex, minCostDP);
if(cost < minCost) {
minCost = cost;
minPrevVertex = prevVertex;
}
}
//this happens for empty subset
if(set.size() == 0) {
minCost = distance[0][currentVertex];
}
minCostDP.put(index, minCost);
parent.put(index, minPrevVertex);
}
}
Set<Integer> set = new HashSet<>();
for(int i=1; i < distance.length; i++) {
set.add(i);
}
int min = Integer.MAX_VALUE;
int prevVertex = -1;
//to avoid ConcurrentModificationException copy set into another set while iterating
Set<Integer> copySet = new HashSet<>(set);
for(int k : set) {
int cost = distance[k][0] + getCost(copySet, k, minCostDP);
if(cost < min) {
min = cost;
prevVertex = k;
}
}
parent.put(Index.createIndex(0, set), prevVertex);
printTour(parent, distance.length);
return min;
}
private void printTour(Map<Index, Integer> parent, int totalVertices) {
Set<Integer> set = new HashSet<>();
for(int i=0; i < totalVertices; i++) {
set.add(i);
}
Integer start = 0;
Deque<Integer> stack = new LinkedList<>();
while(true) {
stack.push(start);
set.remove(start);
start = parent.get(Index.createIndex(start, set));
if(start == null) {
break;
}
}
StringJoiner joiner = new StringJoiner("->");
stack.forEach(v -> joiner.add(String.valueOf(v)));
System.out.println("\nTSP tour");
System.out.println(joiner.toString());
}
private int getCost(Set<Integer> set, int prevVertex, Map<Index, Integer> minCostDP) {
set.remove(prevVertex);
Index index = Index.createIndex(prevVertex, set);
int cost = minCostDP.get(index);
set.add(prevVertex);
return cost;
}
private List<Set<Integer>> generateCombination(int n) {
int input[] = new int[n];
for(int i = 0; i < input.length; i++) {
input[i] = i+1;
}
List<Set<Integer>> allSets = new ArrayList<>();
int result[] = new int[input.length];
generateCombination(input, 0, 0, allSets, result);
Collections.sort(allSets, new SetSizeComparator());
return allSets;
}
private void generateCombination(int input[], int start, int pos, List<Set<Integer>> allSets, int result[]) {
if(pos == input.length) {
return;
}
Set<Integer> set = createSet(result, pos);
allSets.add(set);
for(int i=start; i < input.length; i++) {
result[pos] = input[i];
generateCombination(input, i+1, pos+1, allSets, result);
}
}
private static Set<Integer> createSet(int input[], int pos) {
if(pos == 0) {
return new HashSet<>();
}
Set<Integer> set = new HashSet<>();
for(int i = 0; i < pos; i++) {
set.add(input[i]);
}
return set;
}
}