37. Sudoku Solver(Hard)

本文介绍了一种使用回溯法解决数独问题的算法,并详细解释了如何通过剪枝优化遍历过程,避免无效搜索,最终实现高效求解。

转自个人博客:http://siukwan.sinaapp.com/?p=787
1.这道题目主要是使用回溯法进行遍历,其中需要注意的是进行剪枝。剪枝情况如下:

首先是遍历可以填充的数字,如果遍历完后都没有可以填充,那么就直接回溯,不用继续遍历接下来的空格。

另外最基本的就是用hash检测行列和方块里面的数字是否已经被使用,其中方块数字的index应该为[i/3*3+j/3]。

AC代码如下:

class Solution {
public:
    vector<vector<bool>> HashRow;
    vector<vector<bool>> HashRec;
    vector<vector<bool>> HashCol;
    void dfs(vector<vector<char>>& board,int&leftNumber,bool&isFilled)
    {
        //printfVectorInt2(board);
        //printf("\n");
        if (leftNumber == 0)
            isFilled = true;
        else
        {
            for (int i = 0; i < 9; i++)
            {
                for (int j = 0; j < 9; j++)
                {
                    if (board[i][j] == '.')
                    {
                        bool noNum = true;
                        for (int num = 1; num <= 9; num++)
                        {
                            if (!HashRow[i][num] && !HashCol[j][num] && !HashRec[i / 3 * 3 + j / 3][num])
                            {
                                noNum = false;
                                HashRow[i][num] = true;
                                HashCol[j][num] = true;
                                HashRec[i / 3 * 3 + j / 3][num] = true;

                                leftNumber--;
                                board[i][j] = num+'0';
                                dfs(board, leftNumber, isFilled);
                                if (isFilled)
                                    return;//已经填充成功

                                //填充失败,还原情况
                                board[i][j] = '.';
                                leftNumber++;
                                HashRow[i][num] = false;
                                HashCol[j][num] = false;
                                HashRec[i / 3 * 3 + j / 3][num] = false;
                                noNum = true;
                            }
                        }
                        if (noNum) return;
                    }
                }
            }
        }
    }

    void solveSudoku(vector<vector<char>>& board) {
        HashRow = vector<vector<bool>>(10, vector<bool>(10, false));
        HashRec = vector<vector<bool>>(10, vector<bool>(10, false));
        HashCol = vector<vector<bool>>(10, vector<bool>(10, false));
        vector<int> CountRow(9, 0);
        vector<int> CountRec(9, 0);
        vector<int> CountCol(9, 0);
        int leftNumber = 0;//仍需要填充的数字个数
        for (int i = 0; i < board.size(); i++)
        {
            for (int j = 0; j < board[i].size(); j++)
            {
                if (board[i][j] != '.')
                {//记录已经出现过的数字
                    CountRow[i]++;
                    CountCol[j]++;
                    CountRec[i / 3 * 3 + j / 3]++;
                    HashRow[i][board[i][j]-'0'] = true;
                    HashCol[j][board[i][j]-'0'] = true;
                    HashRec[i / 3 * 3 + j / 3][board[i][j] - '0'] = true;
                }
                else
                    leftNumber++;
            }
        }
        bool isFilled = false;
        dfs(board, leftNumber, isFilled);
    }
};
**方法陈述(5分/5%)** * 将根据所陈述方法在客观上是否连贯一致来评估并给予相应分数; * 方法陈述中术语使用不当将被扣分; * 如果报告中声称所采用的方法与求解器的实际表现之间存在不一致,将被扣分。 **核心算法描述(5分/5%)** * 对所实现算法的理解和阐述程度如何? * 解释是否在概念上进行了适当的概括,或者相反,过于底层、仅根据自身实现的功能来详述算法? * 核心算法的解释是否与优化措施分开说明? **优化措施(5分/5%)** * 对优化措施的解释说明程度如何? * 所采用的优化措施是否复杂精密且数量可观? * 优化措施的成功程度如何?请结合经验性的求解器性能结果,从定性和定量两方面着重说明每项优化措施对降低整体搜索复杂度的贡献。如果尝试通过形式化的理论复杂度降低分析来争取额外加分,请确保在报告中包含完全数学形式化并推导的陈述:对于优化解决方案的复杂度指标,任何未经完整推导而引用的定量陈述将不予给分。 **反思与进一步工作建议(5分/5%)** * 对自身方法成功程度的评估是否到位? * 是否明确指出了其优势与局限性? * 是否提出了合理且有趣的未来工作,以解决具体的局限性? * 所提议的未来工作方法是否在概念上进行了定义?Statement of approach: The Sudoku problem can be regarded as a Constraint Satisfaction Problem.The 81 cells in the Sudoku are variables, with domains ranging from 1 to 9. The constraints are that each row, each column, and each sub-grid can only contain the numbers 1 to 9, and no repetition is allowed.The solver uses backtracking search based on constraint propagation and finding the minimum possible value.It identifies the possible values for the empty cells, then finds the cell with the fewest possible values which is beneficial for constraining the propagation process., and proceeds to solve them one by one. If it fails during the process, it will immediately backtrack. Core algorithm description: The solver employs a backtracking search based on constraint propagation. The set of variables is X={}, represents the cell in which row number and column number are specified. For each variable, possible values are .Firstly, traverse the same row, column, and sub-grid to remove the values that violate the constraints from each variable's domain, obtaining the possible number. This can reduce the search space. During the search process, if a variable is found to be empty or violates a constraint, immediately backtrack and try other values Optimisations: The solver uses a algorithm for finding the minimum number of possible number. At each step, it selects the variable with the fewest possible number for assignment. This helps to find the value of this variable as quickly as possible, because when selecting the cells with a limited possible number, if filling in a number violates the constraints, it can quickly backtrack and reduce the number of invalid assignments. So when solving hard problems, the average time taken is less than one second. Reflections and suggestions for further work: The average solving time of the Sudoku solver is 0.24 seconds, with an accuracy rate of approximately 98%. The performance of the solver is acceptable. It can quickly narrow down the search space and improve the search efficiency. However, the constraint propagation of the solver is weak.Future work will need to enhance the process of restricting the propagation. This can be achieved by immediately checking the variables that are related to a given variable when assigning a value to it, and eliminating the impossible numbers.是否符合要求
最新发布
11-25
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值