Java解决Knights之旅需要很长时间

时间:2020-04-03 13:00:21

标签: java

嘿,所以我要为Springer问题(https://upload.wikimedia.org/wikipedia/commons/8/86/Knight%27s_tour.svg)编写算法

我的代码目前在6x6的字段上不断运行

我们有一个Junit课程来测试它。起始位置为x = 1和y = 1的3x3字段工作正常。

public class Springerproblem {
    private final int xDelta[] = {1,-1,1,-1,2,-2,2,-2};
    private final int yDelta[] = {2,2,-2,-2,1,1,-1,-1};
    /**
     * Datenstruktur zum Abspeichern der Springerzuege
     */
    private int[][] springerFeld;
    private int n0;
    /**
     * Gibt ein zweidimensionales, quadratisches int-Array zurueck. 
     * n ist die Schachbrettbreite.
     * Der Springer startet an Position (x,y) mit 0<=x,y<n.
     * Auf den jeweiligen Postionen des Arrays sind die Positionen des 
     * Springers eingetragen. Die erste Position traegt die 1.
     * Wenn sich das Problem nicht loesen laesst, so wird eine 
     * NoSolutionException geworfen.
     */
    public int[][] springer(int n, int x, int y) throws NoSolutionException{
        springerFeld = new int[n][n]; //erzeuge neues Spielfeld
        this.n0 = n; // übernehme n

        if (spring(x, y, 1)) { //rekursionsende wird im Stack als letztes abgebaut zugNr ist dabei 1 also die Startposition
            return springerFeld;
        }
        else {
            throw new NoSolutionException();
        }
    }

    private boolean spring(int x, int y, int zugnummer) {
         springerFeld[x][y] = zugnummer;//Zugnummer ist am Anfang 1
        if(zugnummer == n0*n0) { //dann ist es am Zeil und teilt methode springer mit dass es fertig ist
            return true;
        }
        for(int i = 0; i < xDelta.length; i++) {
            int newX = x + xDelta[i]; //neue Position x
            int newY = y + yDelta[i]; // neue Position y
            if(loesbar(newX, newY, zugnummer+1)) { // wenn die nächste Position frei ist 
                springerFeld[newX][newY] = zugnummer+1; // füge sie zum weg hinzu
                if(spring(newX, newY, zugnummer+1)) { //rekursionsaufruf mit der nächsten Position
                    return true;
                }
                 // backtracking
            }  
        }
        springerFeld[x][y] = 0;
        return false;
    }

    private boolean loesbar(int x, int y, int zugnummer) {       
        if(0 <= x && x < n0 && 0 <= y && y< n0 && springerFeld[x][y] == 0 && spring(x, y, zugnummer+1)) {
        return true;
    }
    return false;
}
}

方法名称等也无法更改

1 个答案:

答案 0 :(得分:1)

您的算法正确。但是您的loesbar()方法不应调用spring(...),否则您的算法每一步要花费两倍的时间。

同样,要尝试找到单个解决方案的步骤顺序也不是最佳的。 这个问题有同样的问题:Knights tour backtracking lasts too long

使用不同的步骤序列可以更快地找到第一个解决方案:

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

此处给出了说明:Knight's tour backtrack implementation choosing the step array