题目:https://leetcode.com/problems/sudoku-solver/#/description
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.
分析 :基本思路是回溯法。一个比较暴力的方法是,每次从1-9填,然后再判断。稍微好一点的方法是,用set记录每行每列每宫的未填值,然后每次从里面遍历,就不需要从1-9,时间大概在20+ms。更快一点的方法是(虽然我也不知为什么会快一点),用bool visit[81][10]来记录每个点的每个数是否可以访问,但回溯的时候不知道怎么撤销这个修改,所以只在初始的时候记录了一下,后面也是最暴力的,时间在10+ms。更更快的方法,是增加一个贪心,每次先确定当前已经可以确定的数,即当前已经可以排除8个数,时间在3ms。(代码有点凌乱)
c++实现:
void pushToStack(int i, int num[], stack<int> &s,bool visit[][10], int number)
{
++num[i];
visit[i][number] = 1;
if(num[i]==8)
s.push(i);
}
void update(int i, int j, int num[], stack<int> &s, vector< vector<char> >& board, bool visit[][10], int number)
{
for(int k=0; k<9; ++k)
if(board[i][k] == '.' && !visit[i*9+k][number])
pushToStack(i*9+k, num, s, visit, number);
for(int k=0; k<9; ++k)
if(board[k][j] == '.' && !visit[k*9+j][number])
pushToStack(k*9+j, num, s, visit, number);
for(int x=0; x<3; ++x)
for(int y=0; y<3; ++y)
if(board[i/3*3+x][j/3*3+y] == '.' && !visit[(i/3*3+x)*9 + j/3*3+y][number])
pushToStack( (i/3*3+x)*9 + j/3*3+y , num, s, visit, number);
}
void solveSudoku_greedy(vector< vector<char> >& board, bool visit[][10])
{
//每次填已经可以确定的空
int num[81] = {0};
stack<int> s;
for(int i=0; i<9; ++i)
for(int j=0; j<9; ++j)
if(board[i][j] != '.')
{
char c = board[i][j];
int number = board[i][j] - '0';
update(i, j, num, s, board, visit, board[i][j]-'0');
}
int tmp = s.size();
while(!s.empty())
{
int sum = 0;
int index = s.top();
s.pop();
int i=index/9, j=index%9;
int number;
bool visit_tmp[10] = {0};
for(int k=0; k<9; ++k)
{
number = board[i][k]-'0';
if(board[i][k] != '.' && !visit_tmp[number])
{
sum += number;
visit_tmp[number]=1;
}
}
for(int k=0; k<9; ++k)
{
number = board[k][j]-'0';
if(board[k][j] != '.' && !visit_tmp[number])
{
sum += number;
visit_tmp[number]=1;
}
}
for(int x=0; x<3; ++x)
for(int y=0; y<3; ++y)
{
number = board[i/3*3+x][j/3*3+y]-'0';
if(board[i/3*3+x][j/3*3+y] != '.' && !visit_tmp[number])
{
sum += number;
visit_tmp[number]=1;
}
}
board[i][j] = (45-sum)+'0';
update(i, j, num, s, board, visit, board[i][j]-'0');
}
}
void onlyUpdate(int i, int j, vector< vector<char> >& board, bool visit[][10], int number)
{
for(int k=0; k<9; ++k)
visit[i*9+k][number] = 1;
for(int k=0; k<9; ++k)
visit[k*9+j][number] = 1;
for(int x=0; x<3; ++x)
for(int y=0; y<3; ++y)
visit[(i/3*3+x)*9 + j/3*3+y][number] = 1;
}
bool check(int i, int j, vector< vector<char> > &board)
{
for(int k=0; k<9; ++k)
if(j!=k && board[i][k] == board[i][j])
return false;
for(int k=0; k<9; ++k)
if(i!=k && board[k][j] == board[i][j])
return false;
for(int x=0; x<3; ++x)
for(int y=0; y<3; ++y)
if(i/3*3+x!=i && j/3*3+y!=j && board[i/3*3+x][j/3*3+y]==board[i][j])
return false;
return true;
}
bool backtracking(int pos, vector< vector<char> > &board, bool visit[][10])
{
if(pos==81)
return true;
int i=pos/9, j=pos%9;
if(board[i][j] == '.')
{
for(int k=1; k<=9; ++k)
if(!visit[i*9+j][k])
{
board[i][j] = k+'0';
if(check(i, j, board))
if(backtracking(pos+1, board, visit))
return true;
board[i][j] = '.';
}
return false;
}
else
return backtracking(pos+1, board, visit);
}
void solveSudoku(vector< vector<char> >& board)
{
bool visit[81][10] = {0};
solveSudoku_greedy(board, visit);
for(int i=0; i<9; ++i)
for(int j=0; j<9; ++j)
if(board[i][j] != '.')
onlyUpdate(i, j, board, visit, board[i][j]-'0');
backtracking(0, board, visit);
}