zoukankan      html  css  js  c++  java
  • 【Sudoku Solver】cpp

    题目:

    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.

    代码:

    class Solution {
    public:
            void solveSudoku(vector<vector<char> >& board)
            {
                vector<pair<int, int> > emptyCells;
                vector<set<char> > rowSet, colSet, matrixSet;
                set<char> row, col, matrix;
                for ( size_t i = 0 ; i < 9; ++i )
                {
                    row.clear(); col.clear(); matrix.clear();
                    for ( size_t j = 0 ; j < 9; ++j )
                    {
                        if (board[i][j]!='.'){
                            row.insert(board[i][j]);
                        }
                        else{
                            emptyCells.push_back(make_pair(i, j));
                        }
                        if (board[j][i]!='.') col.insert(board[j][i]);
                        int r = j/3+(i/3)*3, c = j%3+(i%3)*3;
                        if (board[r][c]!='.') matrix.insert(board[r][c]);
                    }
                    rowSet.push_back(row); colSet.push_back(col); matrixSet.push_back(matrix);
                }
                Solution::dfs(board, emptyCells, rowSet, colSet, matrixSet);
            }
            static bool dfs(
                vector<vector<char> >& board,
                vector<pair<int, int> >& emptyCell,  
                vector<set<char> >& rowSet,
                vector<set<char> >& colSet,
                vector<set<char> >& matrixSet)
            {
                if ( emptyCell.empty() ) return true;
                int i = emptyCell.back().first;
                int j = emptyCell.back().second;
                for ( char v = '1'; v<='9' && !emptyCell.empty(); ++v )
                {
                    if (rowSet[i].find(v)==rowSet[i].end() && 
                        colSet[j].find(v)==colSet[j].end() &&  
                        matrixSet[(i/3)*3+j/3].find(v)==matrixSet[(i/3)*3+j/3].end() )
                    {
                        board[i][j]=v;
                        rowSet[i].insert(v);
                        colSet[j].insert(v);
                        matrixSet[(i/3)*3+j/3].insert(v);
                        emptyCell.pop_back();
                        if ( Solution::dfs(board, emptyCell, rowSet, colSet, matrixSet) )
                        {
                            return true;
                        }
                        else
                        {
                            emptyCell.push_back(make_pair(i, j));
                            board[i][j] = '.';
                            rowSet[i].erase(v);
                            colSet[j].erase(v);
                            matrixSet[(i/3)*3+j/3].erase(v);
                        }
                    }
                }
                return false;
            }
    };

    tips:

    采用深搜模板。

    主要思路走一遍board,得到三个set,一个vector

    1. 三个set分别为每行、列、子模块已有的数字

    2. 一个vector中存放着'.'的位置

    每次处理一个'.',遍历1到9:

    1. 如果满足数独的条件,就往下走一层

    2. 如果1到9都不满足,则退回到上一层,重新选择上一个位置的元素

    这里有一个思维陷阱:

                        emptyCell.pop_back();
                        if ( Solution::dfs(board, emptyCell, rowSet, colSet, matrixSet) )
                        {
                            return true;
                        }
                        else
                        {
                            emptyCell.push_back(make_pair(i, j));
                            board[i][j] = '.';
                            rowSet[i].erase(v);
                            colSet[j].erase(v);
                            matrixSet[(i/3)*3+j/3].erase(v);
                        }

    注意:pop和push操作应该是对应的,之前一直以为可以不用push的操作,原因是忽略了一种情况:如果一个位置从1到9都不满足,那么必然要回溯到上一层;即,某一个位置的元素是可能遍历不止一次1到9的。

    =================================

    这里set的效率可能有些低,换一个hashmap的效率可能高一些。

    class Solution {
    public:
            void solveSudoku(vector<vector<char> >& board)
            {
                vector<pair<int, int> > emptyCells;
                vector<map<char,bool> > rowSet, colSet, matrixSet;
                map<char,bool> row, col, matrix;
                for ( size_t i = 0 ; i < 9; ++i )
                {
                    for ( char v = '1' ; v <= '9'; ++v ) { row[v] = col[v] = matrix[v] = false; }
                    for ( size_t j = 0 ; j < 9; ++j )
                    {
                        if (board[i][j]!='.'){
                            row[board[i][j]] = true;
                        }
                        else{
                            emptyCells.push_back(make_pair(i, j));
                        }
                        if (board[j][i]!='.') col[board[j][i]]=true;
                        int r = j/3+(i/3)*3, c = j%3+(i%3)*3;
                        if (board[r][c]!='.') matrix[board[r][c]]=true;
                    }
                    rowSet.push_back(row); colSet.push_back(col); matrixSet.push_back(matrix);
                }
                Solution::dfs(board, emptyCells, rowSet, colSet, matrixSet);
            }
            static bool dfs(
                vector<vector<char> >& board,
                vector<pair<int, int> >& emptyCell,  
                vector<map<char,bool> >& rowSet,
                vector<map<char,bool> >& colSet,
                vector<map<char,bool> >& matrixSet)
            {
                if ( emptyCell.empty() ) return true;
                int i = emptyCell.back().first, j = emptyCell.back().second;
                for ( char v = '1'; v<='9'; ++v )
                {
                    if (!rowSet[i][v] && !colSet[j][v] &&  !matrixSet[(i/3)*3+j/3][v] )
                    {
                        board[i][j] = v;
                        rowSet[i][v] = colSet[j][v] = matrixSet[(i/3)*3+j/3][v] = true;
                        emptyCell.pop_back();
                        if ( Solution::dfs(board, emptyCell, rowSet, colSet, matrixSet) ){
                            return true;
                        }
                        else{
                            emptyCell.push_back(make_pair(i, j));
                            rowSet[i][v] = colSet[j][v] = matrixSet[(i/3)*3+j/3][v] = false;
                        }
                    }
                }
                return false;
            }
    };

    tips:都换成了hashmap,效率有所提升。

    ============================================

    第二次过这道题,还是sub board那块内容调了几次,AC了。

    class Solution {
    public:
            void solveSudoku(vector<vector<char> >& board)
            {
                // restore all blank positions
                vector<pair<int, int> > blanks;
                for ( int i=0; i<board.size(); ++i )
                {
                    for ( int j=0; j<board[i].size(); ++j )
                    {
                        if ( board[i][j]=='.' ) blanks.push_back(make_pair(i, j));
                    }
                }
                Solution::dfs(board, blanks);
            }
            static bool dfs(
                vector<vector<char> >& board, 
                vector<pair<int,int> >& blanks )
            {
                if ( blanks.empty() ) return true;
                const int r = blanks.back().first;
                const int c = blanks.back().second;
                for ( char v='1'; v<='9'; ++v )
                {
                    bool valid = true;
                    // check row & column & subBoard
                    for ( int i=0; i<9; ++i )
                    {
                        if ( board[r][i]==v || board[i][c]==v || board[i/3+(r/3)*3][i%3+(c/3)*3]==v )
                        {
                            valid = false;
                            break;
                        }
                    }
                    if ( valid )
                    {
                        board[r][c] = v;
                        blanks.pop_back();
                        if ( Solution::dfs(board, blanks) ) return true;
                        blanks.push_back(make_pair(r, c));
                        board[r][c] = '.';
                    }
                }
                return false;
            }
    };
  • 相关阅读:
    jchdl
    jchdl
    UVa 10256 (判断两个凸包相离) The Great Divide
    UVa 11168 (凸包+点到直线距离) Airport
    LA 2572 (求可见圆盘的数量) Kanazawa
    UVa 10652 (简单凸包) Board Wrapping
    UVa 12304 (6个二维几何问题合集) 2D Geometry 110 in 1!
    UVa 10674 (求两圆公切线) Tangents
    UVa 11796 Dog Distance
    LA 3263 (平面图的欧拉定理) That Nice Euler Circuit
  • 原文地址:https://www.cnblogs.com/xbf9xbf/p/4537044.html
Copyright © 2011-2022 走看看