繁体   English   中英

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

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

我的挑战是用递归和回溯解决给定的数独领域。 我们已经有一些代码,但我们不知道如何实现回溯。 这是我们的代码:

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

removeValueFromField()setValueInField()等方法可以自行解释。 如果没有,我可以向您解释他们的工作。

您对如何在此处实施回溯有想法吗? 问候! 拉斐尔

您必须将之前所做的检查保存在每个单元格的可能值列表中。 最初,所有列表都包含数字 1-9。 初始化后,数独中给定单元的列表减少为一个成员。

然后,主要算法是对所有单元格的循环,您可以将其实现为递归,就像在您的代码中一样。 在此循环中,所有数独约束都应用于每个列表,并删除了不兼容的情况。 例如:假设 cell(1,1) 为 '1',那么我们可以从第 1 行、第 1 列、块 (1,1) 等的所有列表中删除 1。我们循环直到没有不兼容的情况存在。 如果列表之一折叠为零长度,则数独是无法解决的。

如果在这一点 (A) 两个或多个列表的长度保持大于 1,我们选择其中一个列表的可能性之一(例如 p),并再次开始循环。 如果事实证明这是无法解决的,我们从列表中删除 p,返回到 (A)(这是回溯)并尝试第二种可能性,等等。最终我们将达到一个阶段,除了一个列表之外,所有列表的长度都为 1。 如果最后一个列表的长度 > 0,则数独是可解的。

这是一个简化版本,它只是找到了一种可能的解决方案。 您必须自己编写原型函数。

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