【问题标题】:Knight tour problem - order of moves affect performance骑士巡回赛问题 - 移动顺序影响性能
【发布时间】:2018-12-18 21:19:03
【问题描述】:

我试图为骑士之旅问题实施解决方案。我遇到了一个有趣的问题。我想知道这种行为的原因。

这是代码 - 它工作正常。

public class OpenKnightTour {

    private int[][] chessTable;
    private int startRow;
    private int startCol;
    private int ChessBoardSize;


    private final int[][] moves = {
            {-1, -2},
            {-2, -1},
            {-2, 1},
            {-1, 2},
            {1, -2},
            {2, -1},
            {2, 1},
            {1, 2}
    };

    public OpenKnightTour(int ChessBoardSize, int startRow, int startCol){
        this.ChessBoardSize = ChessBoardSize;
        this.startRow = startRow;
        this.startCol = startCol;
        this.chessTable = new int[ChessBoardSize][ChessBoardSize];
    }

    void move(){
        //first move
        this.chessTable[this.startRow][this.startCol] = 1;

        //start with 2nd move recursively
        moveHelper(this.startRow, this.startCol, 2);

        //print results
        this.print();

    }

    private boolean moveHelper(int r, int c, int count){
        if((count-1) == (this.ChessBoardSize * this.ChessBoardSize))
            return true;

        for(int[] move: moves){
            int nextR = r + move[0];
            int nextC = c + move[1];
            if(isMoveValid(nextR, nextC)){
                chessTable[nextR][nextC] = count;
                if(moveHelper(nextR, nextC, count + 1)){
                    return true;
                }
                chessTable[nextR][nextC] = 0;
            }
        }
        return false;
    }

    private void print(){
        Arrays.stream(this.chessTable)
                .forEach(a -> System.out.println(Arrays.toString(a)));
    }

    private boolean isMoveValid(int r, int c){
        if(!(r >= 0 && r < this.ChessBoardSize))
            return false;
        if(!(c >= 0 && c < this.ChessBoardSize))
            return false;
        return chessTable[r][c]==0;
    }

}

现在我们可以运行它,从矩阵中的骑士位置(2, 2) 开始

    OpenKnightTour o = new OpenKnightTour(8, 2, 2);
    o.move();

当我尝试以 (0, 0) 运行起始位置时,它连续运行而没有显示任何结果。所以我认为没有任何解决方案。但是,如果我稍微更改以下顺序,它会立即正常工作。

private final int[][] moves = {
        {-1, -2},
        {-2, -1},
        {-2, 1},
        {-1, 2},
        {1, -2},
        {1, 2}, //moved from last 
        {2, -1},
        {2, 1},
};

到底发生了什么?这种移动位置如何对性能产生如此大的影响?那么在这种情况下,我们如何知道正确的移动顺序呢?

【问题讨论】:

  • 您是否使用调试器单步执行您的代码以检查实际发生的情况?从您的问题中,无需深入研究代码,我可以看到它也可能是一个无限循环,一个特定的测试用例,这种变化会影响速度,在另一种情况下它会降低速度,两者的结合等等。您是否运行了多个(至少数千个)测试以查看此更改何时何地使实际代码更快?你怎么能确定它确实总是更好?
  • 查看这个可爱的debug 博客寻求帮助。

标签: java algorithm recursion backtracking knights-tour


【解决方案1】:

您正在通过一个非常大的搜索空间进行蛮力搜索。如果您的搜索方式不走运,您可能会花费很长时间而没有找到解决方案。

答案是,要么你很幸运地选择了起始地点/起始模式,要么你需要更聪明地识别“无可救药的卡住”。

例如,每回溯 10,000 次,对整个棋盘进行一次扫描。如果你能找到你不可能回到的洞,然后设置一个标志,让你回溯到你可以访问它的最后一步。然后继续。这让您可以跳过一大堆可能无用的工作,然后重新找到要找到的 many possible tours 之一。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-10-28
    • 1970-01-01
    • 1970-01-01
    • 2019-02-04
    • 2022-01-23
    • 2019-07-15
    相关资源
    最近更新 更多