簡體   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