Java 骑士巡演-结果是无限循环,我可以';我不明白为什么

Java 骑士巡演-结果是无限循环,我可以';我不明白为什么,java,algorithm,depth-first-search,backtracking,Java,Algorithm,Depth First Search,Backtracking,我正试图用回溯法解决骑士之旅的问题。我认为我的算法应该有效。我试过了,但我不明白为什么它不起作用。它会导致无限循环 但是,如果我注释掉回溯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 pri

我正试图用回溯法解决骑士之旅的问题。我认为我的算法应该有效。我试过了,但我不明白为什么它不起作用。它会导致无限循环

但是,如果我注释掉回溯
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;
}
private int solutionBoard[][]=new int[8][8];
//骑士可以从任何给定的位置进行的八种可能的移动
私有静态终点[]移动=新点[]{新点(-2,-1),
新点(-2,1),新点(2,-1),新点(2,1),
新点(-1,-2),新点(-1,2),新点(1,-2),
新的点(1,2)};
私有整数计数=0;
公共骑士团{
//棋盘是0-7
//初始化访问

对于(int i=0;i来说,您的算法似乎工作得很好,对于较小的问题实例(如5x5或7x7电路板)产生正确的结果。它似乎是/回溯方法

不过,您可以简化您的
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)
size=7的输出示例(需要将所有代码调整为可变大小!)

更好的方法是:使用维基百科文章中提到的其他算法之一,例如相当简单的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;
}

事实上,对于我尝试过的所有尺寸,调用
findTour
方法的次数正好是
size^2
,也就是说,它在第一次尝试时就找到了巡演,完全没有回溯。

什么意思,当你删除该行时它会起作用?它会终止,还是找到正确的解决方案?你确定它不是非常慢吗?它是termi事实上,ToBiasyk观察到的是正确的:如果不删除你设定的值,你就必须设置重复,在计数达到64之前,自由方块用完,而根本找不到巡视。在中间方块中,5x5板似乎可以正常工作。即使7x7快速完成,表面上看起来是正确的。ion.8x8特别吗?看看你还可以将
findTours
方法改为使用堆栈而不是递归,否则在大于66x66的电路板上会出现
StackOverflowError
。(如果使用启发式方法,第一选择真的一直有效,那么你甚至不需要这样做。)
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;
}
size     findTour calls without and with heuristic
5x5                     76497       25 
7x7                     8947880     49
8x8                     ???         64
20x20                   ???         400