我正在尝试使用回溯来解决骑士的旅行问题。我认为我拥有的算法应该可以工作。我已经尝试过,但是我不知道为什么它不起作用。这导致无限循环。
但是,如果我注释掉回溯的行,solutionBoard[dst.x][dst.y]=-1;它将起作用!我就是不明白为什么!任何帮助,将不胜感激。
solutionBoard[dst.x][dst.y]=-1;
private int solutionBoard[][] = new int [8][8]; // The eight possible moves a knight can make from any given position private static final Point[] MOVES = new Point[] { new Point(-2, -1), new Point(-2, 1), new Point(2, -1), new Point(2, 1), new Point(-1, -2), new Point(-1, 2), new Point(1, -2), new Point(1, 2) }; private int count = 0; public KnightsTour_DFS(){ // board is 0- 7 //initialize visited for(int i =0; i<8;i++){ for(int j = 0; j< 8; j++){ solutionBoard[i][j] = -1; } } solutionBoard[0][0]=count++; if(findTour(0, 0)){ System.out.println("Tour found!!"); printSolution(); } } public boolean findTour(int x, int y){ if(x <0 || y <0 || x>7 || y > 7 ){ return false; } if(count == 64){ //we've covered all node return true; } for(int i = 0; i < this.MOVES.length; i++){ Point dst = new Point(x + MOVES[i].x, y + MOVES[i].y); if(canMove(dst)){ solutionBoard[dst.x][dst.y]=count++; if(findTour(dst.x, dst.y)){ System.out.println("Solution shown on board\n"); return true; } else{ count --; solutionBoard[dst.x][dst.y]=-1; } } } return false; } private void printSolution() { System.out.println("Solution shown on board\n"); for (int[] rows : solutionBoard) { for (int r : rows) { System.out.printf("%2d ", r); } System.out.println(); } } public boolean canMove(Point destination){ if(destination.x<0 || destination.y<0 || destination.x>7|| destination.y>7){ return false; } if(solutionBoard[destination.x][destination.y] != -1){ //already visited return false; } return true; }
您的算法似乎运行良好,可以为较小的问题实例(例如5x5或7x7电路板)提供正确的结果。对于强力 /回溯方法来说,似乎8x8板太大了。
尽管如此,您仍然可以简化findTour方法,使其更易于理解和调试:
findTour
public boolean findTour(int x, int y, int c) { solutionBoard[x][y] = c; if (c == size*size) { return true; } for (Point p : MOVES) { Point dst = new Point(x + p.x, y + p.y); if (canMove(dst) && findTour(dst.x, dst.y, c + 1)) { return true; } } solutionBoard[x][y] = -1; return false; }
findTour(0, 0, 1)with的示例输出size = 7(需要使所有代码适应可变大小!)
findTour(0, 0, 1)
size = 7
1 14 3 38 5 34 7 12 39 10 33 8 37 26 15 2 13 4 25 6 35 40 11 32 9 36 27 44 19 16 21 24 45 48 29 22 41 18 31 28 43 46 17 20 23 42 47 30 49
更好的方法是:使用Wikipedia文章中提到的其他算法之一,例如相当简单的Warnsdorff启发式算法: “我们移动骑士,以便我们始终前进到骑士前进最少的位置。” 我们可以通过排序动作来实现这一目标…
public Point[] sortedPoints(final int x, final int y) { Point[] sorted = Arrays.copyOf(MOVES, MOVES.length); Arrays.sort(sorted, new Comparator<Point>() { public int compare(Point p1, Point p2) { return Integer.signum(nextMoves(p1) - nextMoves(p2)); }; private int nextMoves(Point p) { Point dst = new Point(x + p.x, y + p.y); if (canMove(dst)) { int s = 0; for (Point m : MOVES) { Point dst2 = new Point(dst.x + m.x, dst.y + m.y); if (canMove(dst2)) { s++; } } return s; } else { return 999; } } }); return sorted; }
…,并将后继者循环更改为for (Point p : sortedPoints(x, y))。结果:
for (Point p : sortedPoints(x, y))
size findTour calls without and with heuristic 5x5 76497 25 7x7 8947880 49 8x8 ??? 64 20x20 ??? 400
确实,对于我尝试过的所有尺寸,该findTour方法都称为 精确 size^2时间,即它在第一次尝试时就找到了游览路线,而根本没有回溯。
size^2