这个算法解决数独的时间复杂度是多少?

时间:2014-07-11 19:08:10

标签: c++ algorithm big-o depth-first-search sudoku

  

数独解算器
通过填充空单元格来编写解决数独谜题的程序。

     

空单元格由字符'。'表示。
您可以假设   只有一个独特的解决方案


  我个人认为,
时间复杂度= O((n ^ 2)!),n是电路板的行数(cols)。

  的 C ++

class Solution {
public:
    void solveSudoku(vector<vector<char> > &board) {
        // Input validation.
        if (board.size() == 0 ||
            board.size() != board[0].size() ||
            board.size() % 3 != 0) return;

        helper(board);
    }

    bool helper(vector<vector<char>>& board) {
        // Base case.
        // ... ...

        for (int row = 0; row < board.size(); row ++) {
            for (int col = 0; col < board[0].size(); col ++) {
                if (board[row][col] != '.') continue;

                for (char num = '1'; num <= '9'; num ++) {
                    if (isValid(board, num, row, col)) {
                        // Have a try.
                        board[row][col] = num;

                        // Do recursion.
                        if (helper(board)) return true;;

                        // Roll back.
                        board[row][col] = '.';
                    }
                }
                // Can not find a suitable number[1-9].
                return false;
            }
        }

        return true;
    }

    bool isValid(const vector<vector<char>>& board, char num, int row, int col) {
        // Check row.
        for (int tmp_col = 0; tmp_col < board[0].size(); tmp_col ++) {
            if (board[row][tmp_col] == num) return false;
        }

        // Check col.
        for (int tmp_row = 0; tmp_row < board.size(); tmp_row ++) {
            if (board[tmp_row][col] == num) return false;
        }

        // Check sub square.
        int start_row = (row / 3) * 3;
        int start_col = (col / 3) * 3;
        for (int row = start_row; row < start_row + 3; row ++) {
            for (int col = start_col; col < start_col + 3; col ++) {
                if (board[row][col] == num) return false;
            }
        }

        return true;
    }
};

1 个答案:

答案 0 :(得分:3)

你假设O((n ^ 2)!)的原因是什么?因为它是一个带回溯的经典递归,我会在没有深入分析问题的情况下认为它是O(n ^ n)。尝试创建一个计数器,每次递归调用函数时递增计数器。然后看看算法的最后是否接近387 420 489(我的猜测)或579 712 600 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000(你的猜测)。

如果您想要更复杂的解释,我很乐意给出一个。

编辑: 在考虑详细解释的同时,我注意到我对数字的看法是错误的,它们实际上要高一些。

许多递归搜索可以建模为树。在Sodoku中,每次尝试新字段时都有9种可能性。最多,您必须将解决方案放入所有81个字段。此时,它可以帮助绘制它,以便看到生成的搜索空间是一个树,其深度为81,每个层的每个节点的分支因子为9,并且每个叶子都是可能的解决方案。鉴于这些数字,搜索空间为9 ^ 81。

由于您在尝试81次后没有检查解决方案是否正确,但在每次尝试之后,实际搜索空间会更小。我真的不知道如何把它变成数字,也许每次设置n次尝试时分支因子会变小1,粗略估计。但是如果任何具有k个预设数字的Sodoku,你可以100%确定地说,你最多需要n ^(n²-k)次尝试。

这有意义吗?