文章目录
Sudoku
题目链接:Sudoku
参考博文:数独问题的介绍及POJ 2676-Sudoku(dfs+剪枝)
- 题目大意:
给你一个数独,让你填数:
1.每行的九个数字互不相同;
2.每列的九个数字各不相同;
3.被分成的3*3的小矩阵中的九个数字互不相同;
输出完成后的数表,若不能满足上述条件,则输出原图。 - 思路:这道题大致思路比较好想,但是一直想不到优雅的实现方式,看了上面的博文后,发现了二维数组的用法,典型的用空间换时间。
本道题的重点是三个二维数组的定义- row[i][x]表示第i行中x数字是否已经出现(0/1)。
- col[j][x]表示第j列中x数字是否已经出现(0/1)。
- s[k][x]表示第k个
3
×
3
3\times 3
3×3的小正方形中x数字是否已经出现。
其中 k = 3 × ( ( i − 1 ) / 3 ) + ( j − 1 ) / 3 + 1 k=3\times ((i-1)/3)+(j-1)/3+1 k=3×((i−1)/3)+(j−1)/3+1。(i,j)为该元素的下标。
之后就可以使用dfs来回溯暴力枚举。
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
string str;
int m[10][10], row[10][10], col[10][10], s[10][10];
void Init()
{
memset(row, 0, sizeof(row));
memset(col, 0, sizeof(col));
memset(s, 0, sizeof(s));
}
int get_k(int i, int j)
{
return 3*((i-1)/3)+(j-1)/3+1;
}
int dfs(int x, int y)
{
if(x==10) return 1;
int flag = 0, k = get_k(x, y);
if(m[x][y])//当该位置不需要填值时
{
if(y==9)
flag = dfs(x+1, 1);
else
flag = dfs(x, y+1);
if(flag) return 1;
else return 0;
}
else
{
for(int i=1; i<=9; i++)//暴力枚举数字
{
if(!row[x][i] && !col[y][i] && !s[k][i])//表明该数字可以填
{
row[x][i] = 1, col[y][i] = 1, s[k][i] = 1, m[x][y] = i;
if(y==9)
flag = dfs(x+1, 1);
else
flag = dfs(x, y+1);
if(flag)
return 1;
else//不要忘记将数据还原
row[x][i] = 0, col[y][i] = 0, s[k][i] = 0, m[x][y] = 0;
}
}
}
return 0;
}
int main()
{
int T;
cin >> T;
getchar();
while(T--)
{
Init();
//边输入边标记
for(int i=1; i<=9; i++)
{
getline(cin, str);
str = " "+str;
for(int j=1; j<=9; j++)
{
m[i][j] = str[j]-'0';
if(m[i][j])
{
int k = get_k(i, j);
row[i][m[i][j]] = 1;
col[j][m[i][j]] = 1;
s[k][m[i][j]] = 1;
}
}
}
dfs(1, 1);
for(int i=1; i<=9; i++)
{
for(int j=1; j<=9; j++)
{
printf("%d", m[i][j]);
}
printf("\n");
}
}
return 0;
}