Sudoku Solver

来源:互联网 发布:恒昌利通 知乎 编辑:程序博客网 时间:2024/06/10 20:35

一. Sudoku Solver

Write a program to solve a Sudoku puzzle by filling the empty cells.

Empty cells are indicated by the character ‘.’.

You may assume that there will be only one unique solution.

这里写图片描述

A sudoku puzzle…

这里写图片描述

…and its solution numbers marked in red.

Difficulty:Hard

TIME:35MIN

解法

这道题似乎除了搜索之外,没有特别好的解法,因此我直接写了一个最普通的搜索(没有任何优化),期待着会超时,然而并没有。

搜索的思想当然很简单,就是依次从左到右遍历,发现一个可以填的空位,就选择所有可以填的数字依次填入,当全部填好数字之后,就返回true,否则返回false。

bool dfs(vector<vector<char>>& board) {    vector<char> v(10, 0);    for (int i = 0; i < 9; i++) {        for (int j = 0; j < 9; j++) {            if (board[i][j] == '.') {                for (int k = 0; k < 9; k++) {                    if (board[i][k] != '.')                        v[board[i][k] - '0'] = 1;                    if (board[k][j] != '.')                        v[board[k][j] - '0'] = 1;                    if (board[i / 3 * 3 + k / 3][j / 3 * 3 + k % 3] != '.')                        v[board[i / 3 * 3 + k / 3][j / 3 * 3 + k % 3] - '0'] = 1;                }                for (int k = 1; k <= 9; k++) {                    if (v[k] == 0) {                        board[i][j] = k + '0';                        if (dfs(board)) //如果数独已经解决,就直接返回                            return true;                        board[i][j] = '.';                    }                }                return false;            }        }    }    return true; //程序运行到这里说明这个数独已经解决了}void solveSudoku(vector<vector<char>>& board) {    dfs(board);}

代码的时间复杂度为O(9n),其中n为不确定的位置个数。

优化

虽然这样的解法能过LeetCode,但显然并不是一个特别好的解法,如果是我们自己去解决数独,当然不会从左到右依次遍历,找到空位就填。一般情况下我们都是去找能的填的数字比较少的空位来填,比如某个空位只能填一个数字,那么我们就会优先填那个空位。

因此,这道题最大的可以优化的地方就是,尽量降低搜索树前面结点分叉的数目(把分叉多的放到靠近叶结点的位置,把分叉少的放到靠近根结点的位置)。通过这样的处理,虽然时间复杂度是一样的,但是在解决实际问题的时候速度快了不是一点半点(无形中就减了很多枝)。

而且,从最少可填数目的空位开始填还可以避免冲突的产生,比如有同一行的两个空位,一个可以填3和4,一个只能填3,如果从前面的空位填3,那么后面那一个空位就无论如何也填不了了。而且如果在程序中不对这种情况进行检查的话,可能要等到搜索到很深的地方才能知道这个冲突。但如果是从可填数目最少的空位开始填,就绝对不会产生这种冲突(除非这个数独不可解)。

0 0