简体   繁体   English

在 C 中使用递归和回溯求解数独字段

[英]Solving a Sudoku field with Recursion and Backtracking in C

My challenge is to solve a given Sudoku field with recursion and Backtracking.我的挑战是用递归和回溯解决给定的数独领域。 We already do have some code, but we do not know how to implement the Backtracking.我们已经有一些代码,但我们不知道如何实现回溯。 Here is our Code:这是我们的代码:

int solve( int row, int col ) {
    if (getValueFromField(row, col) != 0) {
        if (col < 8) {
            return solve(row, col + 1);
        }
        if (col == 8) {
            return solve(row + 1, 0);
        }
        if (col == 8 && row == 8) {
            return 1;
        }
    } else {
        for (int i = 1; i <= 9; i++) {
            if (checkValueInField(i, row, col)) {
                setValueInField(i, row, col);
                if (solve(row, col)) {
                    continue;
                }
                return solve(row, col + 1);
            }
        }
        removeValueFromField(row, col);
        return 0;
    }
    return -1;
}

The methods like removeValueFromField() , setValueInField() and so on explain themselves. removeValueFromField()setValueInField()等方法可以自行解释。 If not, I can explain to you what they do.如果没有,我可以向您解释他们的工作。

Do you have an idea on how to implement the Backtracking here?您对如何在此处实施回溯有想法吗? Greetings!问候! Raffael拉斐尔

You have to save the previous checks you made eg in lists of possible values for each cell.您必须将之前所做的检查保存在每个单元格的可能值列表中。 Initially, all lists contain the numbers 1-9.最初,所有列表都包含数字 1-9。 Upon initialization, the lists of the given cells in the sudoku are reduced to one member.初始化后,数独中给定单元的列表减少为一个成员。

The main algorithm then is a loop over all cells, which you might implement as recursion, like in your code.然后,主要算法是对所有单元格的循环,您可以将其实现为递归,就像在您的代码中一样。 In this loop all sudoku-constrains are applied to each list, and incompatible cases are removed.在此循环中,所有数独约束都应用于每个列表,并删除了不兼容的情况。 Eg: Suppose cell(1,1) is '1', then we can remove 1 from all lists in row 1, column 1, block (1,1), etc. We loop until no incompatible case remains.例如:假设 cell(1,1) 为 '1',那么我们可以从第 1 行、第 1 列、块 (1,1) 等的所有列表中删除 1。我们循环直到没有不兼容的情况存在。 If one of the list collapses to zero length, the sudoku is unsolveable.如果列表之一折叠为零长度,则数独是无法解决的。

If at this point (A) the length of two or more lists stays larger than 1, we choose one of the possibilities (say p) of one of those lists, and start the loop again.如果在这一点 (A) 两个或多个列表的长度保持大于 1,我们选择其中一个列表的可能性之一(例如 p),并再次开始循环。 If this turns out to be unsolveable, we remove p from the list, step back to (A) (this is the backtracking) and try the second possibility, etc. Eventually we will reach a stage with all but one lists having length one.如果事实证明这是无法解决的,我们从列表中删除 p,返回到 (A)(这是回溯)并尝试第二种可能性,等等。最终我们将达到一个阶段,除了一个列表之外,所有列表的长度都为 1。 The sudoku is solveable, if this one last list has length > 0.如果最后一个列表的长度 > 0,则数独是可解的。

This is a simplified version which just finds one possible solution.这是一个简化版本,它只是找到了一种可能的解决方案。 You have to program the prototyped functions yourself.您必须自己编写原型函数。

int getListLength(row, col); // number of possible values for this cell, 0...9

void checkConstrains();         // loop all sets (rows, columns, blocks)
                                // and find lists with one element. Remove
                                // this element from all other lists in the set.
                                // Repeat until no duplicates are found.
                        
int *savelist(row, col);        // make a copy of the list
void setlist(row, col, k);      // set list of cell to { k }
getstate(), setstate(s);        // save and set state of the game, ie. all lists
                                


int solve( int row, int col ) {
        int length = getListLength(row, col);
        if(length == 0)
                return 0; // unsolveable
        
        // this is your recursion step slightly
        // reordered to avoid row-overflow
        
        if (col == 8 && row == 8) {
                return 1;
        }
        
        int next_row, next_col;
        if(col < 8) {
                next_row = row;
                next_col = col + 1;
        } else {
                next_row = row + 1;
                next_col = 0;
        }
        
        if(length == 1) {
                return solve(next_row, next_col);
        }
        
        // if we reach this step: length > 1
        checkConstrains();
        
        // length might have changed
        length = getListLength(row, col);
        
        if(length == 0)
                return 0;
        if(length == 1)
                return solve(next_row, next_col);
        
        // still: length > 1
        // backtracking stage
        
        int* list = savelist(row, col);
        sudoku s = getstate();
        
        for(int i = 0; i < length; i++) {
                setstate(s);
                setlist(row, col, list[i]);
                if(solve(row, col))
                        return 1;
        }
        // all elements from list failed-->unsolveable
        // free list and s
        return 0;
}
         

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM