Coincé dans le solveur de retour en arrière Sudoku (Java)


J'essaie de comprendre mon erreur dans le solveur de retour en arrière Sudoku depuis trois jours. Le problème vient du solveur de Sudoku leetcode .

Mon solveur est basé sur la déduction dans l'image ci-jointe. Le problème est que mon tableau est modifié même si un chemin de la racine à la feuille n'est pas valide.

En d'autres termes, après qu'il passe par un chemin invalide, les valeurs qu'il a tentées sont corrigées dans mon tableau d'origine. Cependant, je ne mets à jour mon tableau d'origine que lorsque ses enfants renvoie true (voir la partie dans la méthode helper: // mettre un nombre et générer des enfants).

Fondamentalement, pour chaque".', Je génère toutes les possibilités de 1 à 9, construire une carte temporaire qui remplit le courant'.'avec une possibilité, puis appelez l'assistant du suivant'.'avec le temp conseil d'administration. Je sais qu'il n'est pas bon de stocker un boardTemp de même taille pour chaque enfant possible en raison du coût de l'espace, mais ma principale préoccupation est maintenant de résoudre le problème avant d'optimiser le coût.

Dans l'Ensemble, pourquoi mon tableau change-t-il même si tous les enfants ne sont pas valides?

Par exemple, base sur la carte initiale

..9748...; 7........; .2.1.9...;

..7...24.; .64.1.59.; .98...3..;

...8.3.2.; ........6; ...2759..;

J'ai obtenu le résultat final après avoir exécuté:

139748652; 745326189; 826159437;

35769.24.; .64.1.59.; .98...3..;

...8.3.2.; ........6; ...2759..;

public void sudokuSolver(char[][] board) {
    for (int i = 0 ; i < board.length ; i++) {
        for (int j = 0 ; j < board.length ; j++) {
            if (board[i][j] == '.') {
                // find the first '.' as root
                helper(i, j, board);
                return;
            }
        }
    }
}

private boolean helper(int row, int col, char[][] board) {
    // case 2. check if it has following '.' and store its position
    boolean hasNext = false;
    boolean nextSearching = false;
    int nextRow = row;
    int nextCol = col;
    for (int i = 0 ; i < board.length ; i++) {
        for (int j = 0; j < board.length ; j++) {
            if (nextSearching && !hasNext && board[i][j] == '.') {
                hasNext = true; // there is next!
                nextRow = i;
                nextCol = j;
            }
            if (i == row && j == col) {
                nextSearching = true;
            }
        }
    }

    // exit condition: last '.'
    if (!hasNext) {
        for (char put = '1' ; put <= '9' ; put ++) {
            if (isValid(row, col, board, put)) {
                return true;
            }
        }
        return false;
    }

    // put a number and generate children
    for (char put = '1' ; put <= '9' ; put ++) {
        if (isValid(row, col, board, put)) {
            char[][] boardTemp = board;
            boardTemp[row][col] = put;
            boolean valid = helper(nextRow, nextCol, boardTemp);
            if (valid) {
                // board is supposed to change only when valid is true.
                board[row][col] = put;
                return true;
            }
        }
    }
    return false;
}

private boolean isValid(int row, int col, char[][] board, char c) {
    // go through each row, column, and subblock to determine if c is a valid choice based on current board.
    for (int jCol = 0 ; jCol < 9 ; jCol ++) {
        if (board[row][jCol] == c) {
            return false;
        }
    }
    for (int iRow = 0 ; iRow < 9 ; iRow ++) {
        if (board[iRow][col] == c) {
            return false;
        }
    }
    for (int i = row/3*3 ; i < row/3*3 + 3 ; i++) {
        for (int j = col/3*3 ; j < col/3*3 + 3 ; j++) {
            if (board[i][j] == c) {
                return false;
            }
        }
    }
    return true;
}

Mon arbre pour revenir en arrière

Author: Holger Just, 2016-08-10

1 answers

Il n'y a pas de différence entre l'utilisation de boardTemp et board. char[][] boardTemp = board signifie qu'ils pointent vers la même mémoire... Ce que vous avez manqué dans votre code d'origine est la partie else après avoir mis un numéro invalide:

for (char put = '1' ; put <= '9' ; put ++) {
    if (isValid(row, col, board, put)) {
        char[][] boardTemp = board; // board and boardTemp are essentially the same thing
        boardTemp[row][col] = put;
        boolean valid = helper(nextRow, nextCol, boardTemp);
        if (valid) {
            // board is supposed to change only when valid is true.
            board[row][col] = put;
            return true;
        }
        // THIS IS WHAT YOU MISSED!!
        // if you don't reset the '.' back, your later backtrack will not work 
        // because you put an invalid number on your board and you will never find a solution
        boardTemp[row][col] = '.';
    }
}
 4
Author: Shawn Song, 2016-08-10 07:36:23