import java.util.*; public class TravelingSalesmanHeldKarp { private static int INFINITY = 100000000; private static class Index { int currentVertex; Set 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 vertexSet) { Index i = new Index(); i.currentVertex = vertex; i.vertexSet = vertexSet; return i; } } private static class SetSizeComparator implements Comparator>{ @Override public int compare(Set o1, Set o2) { return o1.size() - o2.size(); } } public int minCost(int[][] distance) { //stores intermediate values in map Map minCostDP = new HashMap<>(); Map parent = new HashMap<>(); List> allSets = generateCombination(distance.length - 1); for(Set 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 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 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 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 parent, int totalVertices) { Set set = new HashSet<>(); for(int i=0; i < totalVertices; i++) { set.add(i); } Integer start = 0; Deque 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 set, int prevVertex, Map minCostDP) { set.remove(prevVertex); Index index = Index.createIndex(prevVertex, set); int cost = minCostDP.get(index); set.add(prevVertex); return cost; } private List> generateCombination(int n) { int input[] = new int[n]; for(int i = 0; i < input.length; i++) { input[i] = i+1; } List> 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> allSets, int result[]) { if(pos == input.length) { return; } Set 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 createSet(int input[], int pos) { if(pos == 0) { return new HashSet<>(); } Set set = new HashSet<>(); for(int i = 0; i < pos; i++) { set.add(input[i]); } return set; } }