|
@@ -5,50 +5,23 @@ import pathgame.tilemap.TileMap;
|
|
import java.util.ArrayList;
|
|
import java.util.ArrayList;
|
|
import java.util.Collections;
|
|
import java.util.Collections;
|
|
|
|
|
|
-/**
|
|
|
|
- * Class for calculating an approximation of the travelling salesman problem, using the Christofides algorithm
|
|
|
|
- *
|
|
|
|
- */
|
|
|
|
public class TravellingSalesAlg {
|
|
public class TravellingSalesAlg {
|
|
- /**
|
|
|
|
- * Calculates an approximation of the travelling salesman problem, using the Christofides algorithm
|
|
|
|
- *
|
|
|
|
- * @param map the TileMap that the algorithm should be used on
|
|
|
|
- * @param player that is traversing the map
|
|
|
|
- * @return
|
|
|
|
- */
|
|
|
|
public static int calcSalesPathLen(TileMap map, Player player) {
|
|
public static int calcSalesPathLen(TileMap map, Player player) {
|
|
DijkstraMagic dijkstra = new DijkstraMagic(map, player);
|
|
DijkstraMagic dijkstra = new DijkstraMagic(map, player);
|
|
-
|
|
|
|
ArrayList<ArrayList<SaleRoute>> salesPitch = dijkstra.getSalesPitch();
|
|
ArrayList<ArrayList<SaleRoute>> salesPitch = dijkstra.getSalesPitch();
|
|
-
|
|
|
|
- //make minimum spanning tree
|
|
|
|
ArrayList<TreeEdge> MSTree = makeMSTree(salesPitch);
|
|
ArrayList<TreeEdge> MSTree = makeMSTree(salesPitch);
|
|
-
|
|
|
|
- //find pairs-shortest path for verteces with odd degree and add those edges to MSTree
|
|
|
|
ArrayList<TreeEdge> oddDegEdges = makeOddDegEdges(MSTree, salesPitch);
|
|
ArrayList<TreeEdge> oddDegEdges = makeOddDegEdges(MSTree, salesPitch);
|
|
MSTree.addAll(oddDegEdges);
|
|
MSTree.addAll(oddDegEdges);
|
|
-
|
|
|
|
- //finde euler tour
|
|
|
|
ArrayList<Integer> eulerTour = getEulerTour(MSTree);
|
|
ArrayList<Integer> eulerTour = getEulerTour(MSTree);
|
|
-
|
|
|
|
- //cut short
|
|
|
|
cutShort(eulerTour);
|
|
cutShort(eulerTour);
|
|
-
|
|
|
|
- //calculate the total weight of the tour using the edge table (salesPitch)
|
|
|
|
int tourWeight = calcTourWeight(eulerTour, salesPitch);
|
|
int tourWeight = calcTourWeight(eulerTour, salesPitch);
|
|
return tourWeight;
|
|
return tourWeight;
|
|
-
|
|
|
|
- //brute force
|
|
|
|
- //return bruteForce(salesPitch);
|
|
|
|
}
|
|
}
|
|
|
|
|
|
private static int calcTourWeight(ArrayList<Integer> tour, ArrayList<ArrayList<SaleRoute>> salesPitch) {
|
|
private static int calcTourWeight(ArrayList<Integer> tour, ArrayList<ArrayList<SaleRoute>> salesPitch) {
|
|
int totalWeight = 0;
|
|
int totalWeight = 0;
|
|
-
|
|
|
|
for(int i = 0; i < tour.size() - 1; i++) {
|
|
for(int i = 0; i < tour.size() - 1; i++) {
|
|
int startNode, endNode;
|
|
int startNode, endNode;
|
|
-
|
|
|
|
if(tour.get(i) < tour.get(i + 1)) {
|
|
if(tour.get(i) < tour.get(i + 1)) {
|
|
startNode = tour.get(i);
|
|
startNode = tour.get(i);
|
|
endNode = tour.get(i + 1) - startNode - 1;
|
|
endNode = tour.get(i + 1) - startNode - 1;
|
|
@@ -63,19 +36,15 @@ public class TravellingSalesAlg {
|
|
|
|
|
|
private static void cutShort(ArrayList<Integer> eulerTour) {
|
|
private static void cutShort(ArrayList<Integer> eulerTour) {
|
|
int counter = 2;
|
|
int counter = 2;
|
|
-
|
|
|
|
while(counter < eulerTour.size() - 1) {
|
|
while(counter < eulerTour.size() - 1) {
|
|
int current = eulerTour.get(counter);
|
|
int current = eulerTour.get(counter);
|
|
-
|
|
|
|
boolean found = false;
|
|
boolean found = false;
|
|
-
|
|
|
|
for(int i = 0; i < counter; i++) {
|
|
for(int i = 0; i < counter; i++) {
|
|
if(eulerTour.get(i) == current) {
|
|
if(eulerTour.get(i) == current) {
|
|
found = true;
|
|
found = true;
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
-
|
|
|
|
if(found) {
|
|
if(found) {
|
|
eulerTour.remove(counter);
|
|
eulerTour.remove(counter);
|
|
} else {
|
|
} else {
|
|
@@ -86,13 +55,11 @@ public class TravellingSalesAlg {
|
|
|
|
|
|
private static ArrayList<Integer> getEulerTour(ArrayList<TreeEdge> graph) {
|
|
private static ArrayList<Integer> getEulerTour(ArrayList<TreeEdge> graph) {
|
|
ArrayList<Integer> tour = new ArrayList<>();
|
|
ArrayList<Integer> tour = new ArrayList<>();
|
|
-
|
|
|
|
while(graph.size() > 0) {
|
|
while(graph.size() > 0) {
|
|
- if(tour.size() == 0) {
|
|
|
|
|
|
+ if(tour.isEmpty()) {
|
|
tour = getSubtour(graph, graph.get(0).getSrc());
|
|
tour = getSubtour(graph, graph.get(0).getSrc());
|
|
} else {
|
|
} else {
|
|
int start = -1;
|
|
int start = -1;
|
|
-
|
|
|
|
for(int e = 0; e < graph.size(); e++) {
|
|
for(int e = 0; e < graph.size(); e++) {
|
|
TreeEdge edge = graph.get(e);
|
|
TreeEdge edge = graph.get(e);
|
|
for(int tp = 0; tp < tour.size(); tp++) {
|
|
for(int tp = 0; tp < tour.size(); tp++) {
|
|
@@ -108,32 +75,26 @@ public class TravellingSalesAlg {
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
-
|
|
|
|
ArrayList<Integer> subTour = getSubtour(graph, start);
|
|
ArrayList<Integer> subTour = getSubtour(graph, start);
|
|
-
|
|
|
|
mergeTours(tour, subTour);
|
|
mergeTours(tour, subTour);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
-
|
|
|
|
return tour;
|
|
return tour;
|
|
}
|
|
}
|
|
|
|
|
|
private static ArrayList<Integer> getSubtour(ArrayList<TreeEdge> graph, int start) {
|
|
private static ArrayList<Integer> getSubtour(ArrayList<TreeEdge> graph, int start) {
|
|
ArrayList<Integer> tour = new ArrayList<>();
|
|
ArrayList<Integer> tour = new ArrayList<>();
|
|
tour.add(start);
|
|
tour.add(start);
|
|
-
|
|
|
|
int pos = nextTourEdgePos(graph, start);
|
|
int pos = nextTourEdgePos(graph, start);
|
|
int next = graph.get(pos).getOtherVertex(start);
|
|
int next = graph.get(pos).getOtherVertex(start);
|
|
graph.remove(pos);
|
|
graph.remove(pos);
|
|
tour.add(next);
|
|
tour.add(next);
|
|
-
|
|
|
|
while(next != start) {
|
|
while(next != start) {
|
|
pos = nextTourEdgePos(graph, next);
|
|
pos = nextTourEdgePos(graph, next);
|
|
next = graph.get(pos).getOtherVertex(next);
|
|
next = graph.get(pos).getOtherVertex(next);
|
|
graph.remove(pos);
|
|
graph.remove(pos);
|
|
tour.add(next);
|
|
tour.add(next);
|
|
}
|
|
}
|
|
-
|
|
|
|
return tour;
|
|
return tour;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -143,21 +104,17 @@ public class TravellingSalesAlg {
|
|
return i;
|
|
return i;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
-
|
|
|
|
return -1;
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
|
|
private static void mergeTours(ArrayList<Integer> tour, ArrayList<Integer> subTour) {
|
|
private static void mergeTours(ArrayList<Integer> tour, ArrayList<Integer> subTour) {
|
|
int mergeTo = subTour.get(0);
|
|
int mergeTo = subTour.get(0);
|
|
-
|
|
|
|
int mergePos = -1;
|
|
int mergePos = -1;
|
|
-
|
|
|
|
for(int i = 0; i < tour.size(); i++) {
|
|
for(int i = 0; i < tour.size(); i++) {
|
|
if(tour.get(i) == mergeTo) {
|
|
if(tour.get(i) == mergeTo) {
|
|
mergePos = i;
|
|
mergePos = i;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
-
|
|
|
|
for(int i = subTour.size() - 1; i > 0; i--) {
|
|
for(int i = subTour.size() - 1; i > 0; i--) {
|
|
tour.add(mergePos + 1, subTour.get(i));
|
|
tour.add(mergePos + 1, subTour.get(i));
|
|
}
|
|
}
|
|
@@ -165,40 +122,26 @@ public class TravellingSalesAlg {
|
|
|
|
|
|
private static ArrayList<TreeEdge> makeOddDegEdges(ArrayList<TreeEdge> msTree, ArrayList<ArrayList<SaleRoute>> salesPitch) {
|
|
private static ArrayList<TreeEdge> makeOddDegEdges(ArrayList<TreeEdge> msTree, ArrayList<ArrayList<SaleRoute>> salesPitch) {
|
|
int numOfEdges[] = new int[salesPitch.size()];
|
|
int numOfEdges[] = new int[salesPitch.size()];
|
|
-
|
|
|
|
for(int i = 0; i < msTree.size(); i++) {
|
|
for(int i = 0; i < msTree.size(); i++) {
|
|
numOfEdges[msTree.get(i).getSrc()]++;
|
|
numOfEdges[msTree.get(i).getSrc()]++;
|
|
numOfEdges[msTree.get(i).getDest()]++;
|
|
numOfEdges[msTree.get(i).getDest()]++;
|
|
}
|
|
}
|
|
-
|
|
|
|
OddDegreeList oddDegs = new OddDegreeList();
|
|
OddDegreeList oddDegs = new OddDegreeList();
|
|
-
|
|
|
|
for(int i = 0; i < numOfEdges.length; i++) {
|
|
for(int i = 0; i < numOfEdges.length; i++) {
|
|
- //System.out.println(numOfEdges[i]);
|
|
|
|
if(numOfEdges[i] % 2 == 1) {
|
|
if(numOfEdges[i] % 2 == 1) {
|
|
oddDegs.add(i);
|
|
oddDegs.add(i);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
-
|
|
|
|
Permutation permut = new Permutation(oddDegs.size(), 2);
|
|
Permutation permut = new Permutation(oddDegs.size(), 2);
|
|
-
|
|
|
|
calcPairShortest(oddDegs, salesPitch, permut, 0, 0);
|
|
calcPairShortest(oddDegs, salesPitch, permut, 0, 0);
|
|
permut.makePermutMinimal();
|
|
permut.makePermutMinimal();
|
|
-
|
|
|
|
- //System.out.println(permut.tempCounter1);
|
|
|
|
- //System.out.println(permut.tempCounter2);
|
|
|
|
- //System.out.println("min cost: " + permut.getMinCost());
|
|
|
|
- //permut.printPermut();
|
|
|
|
ArrayList<TreeEdge> oddEdges = new ArrayList<>();
|
|
ArrayList<TreeEdge> oddEdges = new ArrayList<>();
|
|
oddDegs.resetUsed();
|
|
oddDegs.resetUsed();
|
|
for(int i = 0; i < permut.size(); i++) {
|
|
for(int i = 0; i < permut.size(); i++) {
|
|
int offSet = permut.getValAtPos(i);
|
|
int offSet = permut.getValAtPos(i);
|
|
-
|
|
|
|
addOddEdge(oddEdges, oddDegs, salesPitch, offSet);
|
|
addOddEdge(oddEdges, oddDegs, salesPitch, offSet);
|
|
}
|
|
}
|
|
-
|
|
|
|
addOddEdge(oddEdges, oddDegs, salesPitch, 0);
|
|
addOddEdge(oddEdges, oddDegs, salesPitch, 0);
|
|
-
|
|
|
|
return oddEdges;
|
|
return oddEdges;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -207,39 +150,24 @@ public class TravellingSalesAlg {
|
|
oddDegs.makeOffsetUsed(0);
|
|
oddDegs.makeOffsetUsed(0);
|
|
int dest = oddDegs.getUnused(offSet);
|
|
int dest = oddDegs.getUnused(offSet);
|
|
oddDegs.makeOffsetUsed(offSet);
|
|
oddDegs.makeOffsetUsed(offSet);
|
|
-
|
|
|
|
oddEdges.add(new TreeEdge(orig, dest, salesPitch.get(orig).get(dest - orig - 1).getTotalCost()));
|
|
oddEdges.add(new TreeEdge(orig, dest, salesPitch.get(orig).get(dest - orig - 1).getTotalCost()));
|
|
}
|
|
}
|
|
|
|
|
|
private static void calcPairShortest(OddDegreeList oddDegs, ArrayList<ArrayList<SaleRoute>> salesPitch, Permutation permut, int permutPos, int costSoFar) {
|
|
private static void calcPairShortest(OddDegreeList oddDegs, ArrayList<ArrayList<SaleRoute>> salesPitch, Permutation permut, int permutPos, int costSoFar) {
|
|
while(true) {
|
|
while(true) {
|
|
int offSet;
|
|
int offSet;
|
|
-
|
|
|
|
if(permutPos == permut.size()) {
|
|
if(permutPos == permut.size()) {
|
|
offSet = 0;
|
|
offSet = 0;
|
|
} else {
|
|
} else {
|
|
offSet = permut.getValAtPos(permutPos);
|
|
offSet = permut.getValAtPos(permutPos);
|
|
}
|
|
}
|
|
-
|
|
|
|
int orig = oddDegs.getUnused(0);
|
|
int orig = oddDegs.getUnused(0);
|
|
int dest = oddDegs.getUnused(1 + offSet);
|
|
int dest = oddDegs.getUnused(1 + offSet);
|
|
-
|
|
|
|
int edgeWeight = salesPitch.get(orig).get(dest - orig - 1).getTotalCost();
|
|
int edgeWeight = salesPitch.get(orig).get(dest - orig - 1).getTotalCost();
|
|
int newCost = costSoFar + edgeWeight;
|
|
int newCost = costSoFar + edgeWeight;
|
|
- //permut.tempCounter1++;
|
|
|
|
-
|
|
|
|
- /*System.out.println();
|
|
|
|
- System.out.println("permut pos: " + permutPos);
|
|
|
|
- System.out.println(orig + " : " + dest);
|
|
|
|
- System.out.println("newCost: " + newCost);
|
|
|
|
- permut.printPermut();*/
|
|
|
|
if(newCost < permut.getMinCost()) {
|
|
if(newCost < permut.getMinCost()) {
|
|
if(permutPos == permut.size()) {
|
|
if(permutPos == permut.size()) {
|
|
permut.setMinCost(newCost);
|
|
permut.setMinCost(newCost);
|
|
- /*System.out.println();
|
|
|
|
- System.out.println("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
|
|
|
|
- System.out.println("New Min: " + newCost);
|
|
|
|
- System.out.println("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");*/
|
|
|
|
} else {
|
|
} else {
|
|
int used1 = oddDegs.makeOffsetUsed(0);
|
|
int used1 = oddDegs.makeOffsetUsed(0);
|
|
int used2 = oddDegs.makeOffsetUsed(offSet);
|
|
int used2 = oddDegs.makeOffsetUsed(offSet);
|
|
@@ -248,15 +176,12 @@ public class TravellingSalesAlg {
|
|
oddDegs.makeUnused(used2);
|
|
oddDegs.makeUnused(used2);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
-
|
|
|
|
if(permutPos == permut.size()) {
|
|
if(permutPos == permut.size()) {
|
|
- //permut.tempCounter2++;
|
|
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
if(permut.isPosAtMax(permutPos)) {
|
|
if(permut.isPosAtMax(permutPos)) {
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
-
|
|
|
|
permut.increaseAtPos(permutPos);
|
|
permut.increaseAtPos(permutPos);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
@@ -264,29 +189,19 @@ public class TravellingSalesAlg {
|
|
private static ArrayList<TreeEdge> makeMSTree(ArrayList<ArrayList<SaleRoute>> salesPitch) {
|
|
private static ArrayList<TreeEdge> makeMSTree(ArrayList<ArrayList<SaleRoute>> salesPitch) {
|
|
ArrayList<TreeEdge> allEdges = new ArrayList<>();
|
|
ArrayList<TreeEdge> allEdges = new ArrayList<>();
|
|
ArrayList<TreeEdge> msTree = new ArrayList<>();
|
|
ArrayList<TreeEdge> msTree = new ArrayList<>();
|
|
-
|
|
|
|
int vertNum = salesPitch.size();
|
|
int vertNum = salesPitch.size();
|
|
-
|
|
|
|
for(int orig = 0; orig < salesPitch.size(); orig++) {
|
|
for(int orig = 0; orig < salesPitch.size(); orig++) {
|
|
for(int dest = 0; dest < salesPitch.get(orig).size(); dest++) {
|
|
for(int dest = 0; dest < salesPitch.get(orig).size(); dest++) {
|
|
allEdges.add(new TreeEdge(orig, dest + 1 + orig, salesPitch.get(orig).get(dest).getTotalCost()));
|
|
allEdges.add(new TreeEdge(orig, dest + 1 + orig, salesPitch.get(orig).get(dest).getTotalCost()));
|
|
- //System.out.println(edge.getSrc() + " " + edge.getDest() + " " + edge.getWeight());
|
|
|
|
- //System.out.println(salesPitch.get(orig).get(dest).getTotalCost());
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
-
|
|
|
|
- //System.out.println(vertNum);
|
|
|
|
Collections.sort(allEdges);
|
|
Collections.sort(allEdges);
|
|
-
|
|
|
|
while(msTree.size() < vertNum - 1) {
|
|
while(msTree.size() < vertNum - 1) {
|
|
-
|
|
|
|
if(notCycle(msTree, allEdges.get(0))) {
|
|
if(notCycle(msTree, allEdges.get(0))) {
|
|
msTree.add(allEdges.get(0));
|
|
msTree.add(allEdges.get(0));
|
|
- //System.out.println(allEdges.get(0).getSrc() + " " + allEdges.get(0).getDest() + " " + allEdges.get(0).getWeight());
|
|
|
|
}
|
|
}
|
|
allEdges.remove(0);
|
|
allEdges.remove(0);
|
|
}
|
|
}
|
|
-
|
|
|
|
return msTree;
|
|
return msTree;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -296,7 +211,6 @@ public class TravellingSalesAlg {
|
|
if(edge.getSrc() == vertex || edge.getDest() == vertex) {
|
|
if(edge.getSrc() == vertex || edge.getDest() == vertex) {
|
|
if(!edge.isChecked()) {
|
|
if(!edge.isChecked()) {
|
|
edgeQ.add(edge);
|
|
edgeQ.add(edge);
|
|
- //System.out.println("src: " + edge.getSrc() + "; dest: " + edge.getDest());
|
|
|
|
edge.setChecked(true);
|
|
edge.setChecked(true);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
@@ -307,9 +221,7 @@ public class TravellingSalesAlg {
|
|
ArrayList<TreeEdge> edgeQ = new ArrayList<>();
|
|
ArrayList<TreeEdge> edgeQ = new ArrayList<>();
|
|
int dest = additon.getDest();
|
|
int dest = additon.getDest();
|
|
resetEdges(tree);
|
|
resetEdges(tree);
|
|
-
|
|
|
|
qEdges(tree, edgeQ, additon.getSrc());
|
|
qEdges(tree, edgeQ, additon.getSrc());
|
|
-
|
|
|
|
while(edgeQ.size() > 0) {
|
|
while(edgeQ.size() > 0) {
|
|
TreeEdge edge = edgeQ.get(0);
|
|
TreeEdge edge = edgeQ.get(0);
|
|
edgeQ.remove(0);
|
|
edgeQ.remove(0);
|
|
@@ -320,7 +232,6 @@ public class TravellingSalesAlg {
|
|
qEdges(tree, edgeQ, edge.getDest());
|
|
qEdges(tree, edgeQ, edge.getDest());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
-
|
|
|
|
return true;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
|