簡體   English   中英

騎士巡回賽-導致無限循環,我不知道為什么

[英]Knights tour - results in an infinite loop and i can't figure out why

我正在嘗試使用回溯來解決騎士的旅行問題。 我認為我擁有的算法應該可以工作。 我已經嘗試過,但是我不知道為什么它不起作用。 這導致無限循環。

但是,如果我注釋掉回溯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方法,使其更易於理解和調試:

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;
}

size = 7 findTour(0, 0, 1)示例輸出(需要使所有代碼適應可變大小!)

 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)) 結果:

size     findTour calls without and with heuristic
5x5                     76497       25 
7x7                     8947880     49
8x8                     ???         64
20x20                   ???         400

確實,對於我嘗試過的所有大小, findTour方法都被准確地調用size^2次,即它在第一次嘗試時就找到了游覽,根本沒有回溯。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM