Sudoku(POJ2676)是一种简单的数字游戏,一个9×9的正方形表格被分成9个3×3的小正方形表格,在表格的某些单元格中,已填有数字1至9中的一个。游戏的任务是,在表格每一个空白单元格里填入数字1至9中的一个,使得9×9正方形表格的每一行和每一列以及9个3×3小正方形表格中,数字1至9都出现且仅出现一次。
你的任务是,编程求出给定Sudoku游戏的一种填法。例如,图1(a)游戏的一个解如图1(b)所示。
1 | 3 | 5 | 9 | |||||
2 | 1 | 9 | 4 | |||||
7 | 4 | |||||||
3 | 5 | 2 | 6 | |||||
6 | 5 | |||||||
7 | 8 | 3 | 4 | |||||
4 | 1 | |||||||
9 | 2 | 5 | 8 | |||||
8 | 4 | 1 | 7 |
(a)
1 | 4 | 3 | 6 | 2 | 8 | 5 | 7 | 9 |
5 | 7 | 2 | 1 | 3 | 9 | 4 | 6 | 8 |
9 | 8 | 6 | 7 | 5 | 4 | 2 | 3 | 1 |
3 | 9 | 1 | 5 | 4 | 2 | 7 | 8 | 6 |
4 | 6 | 8 | 9 | 1 | 7 | 3 | 5 | 2 |
7 | 2 | 5 | 8 | 6 | 3 | 9 | 1 | 4 |
2 | 3 | 7 | 4 | 8 | 1 | 6 | 9 | 5 |
6 | 1 | 9 | 2 | 7 | 5 | 8 | 4 | 3 |
8 | 5 | 4 | 3 | 9 | 6 | 1 | 2 | 7 |
(b)
思路:用深搜法,两种方法,后一种是对前一种的优化。
代码如下:
#include <iostream>
using namespace std;
int map[10][10];//九宫格
//row[i][x] 标记在第i行中数字x是否出现了
//col[j][y] 标记在第j列中数字y是否出现了
//box[k][z] 标记在第k个3*3子格中数字z是否出现了
bool row[10][10],col[10][10],box[10][10];
bool DFS(int x,int y)
{
if (x == 10)
return true;
bool flag = false;
if (map[x][y])
{
if (y == 9)
flag = DFS(x + 1,1);
else
flag = DFS(x,y + 1);
if (flag)//回溯
return true;
else
return false;
}
else
{
int k = 3 * ((x - 1) / 3) + (y - 1) / 3 + 1;
for (int i = 1; i <= 9; i++)
if (!row[x][i] && !col[y][i] && !box[k][i])
{
map[x][y] = i;
row[x][i] = true;
col[y][i] = true;
box[k][i] = true;
if (9 == y)
flag = DFS(x + 1,1);
else
flag = DFS(x,y + 1);
if (!flag)//回溯
{
map[x][y] = 0;
row[x][i] = false;
col[y][i] = false;
box[k][i] = false;
}
else
return true;
}
}
return false;
}
int main()
{
int T,i,j;
cin>>T;
while (T--)
{
memset(row,false,sizeof(row));
memset(col,false,sizeof(col));
memset(box,false,sizeof(box));
for (i = 1; i <= 9; i++)
for (j = 1; j <= 9; j++)
{
cin>>map[i][j];
if (map[i][j])
{
int k = 3 * ((i - 1) / 3) + (j - 1) / 3 + 1;
row[i][map[i][j]] = true;
col[j][map[i][j]] = true;
box[k][map[i][j]] = true;
}
}
DFS(1,1);
for (i = 1; i <= 9; i++)
{
for (j = 1; j <= 9; j++)
cout<<map[i][j];
cout<<endl;
}
}
return 0;
}
我们可以对以上代码进行优化,不需要每一个位置都要遍历,只遍历未填充数字的位置,代码如下:
#include <cstdio>
#include <cstring>
int row[9][10],col[9][10],box[9][10];
int map[9][9],pos[81][2],p,n;//place记录哪些位置需要填写
int DFS(int x,int y)
{
int i,j;
if (p == n)
{
for (i = 0 ; i < 9; i++)
{
for (j = 0; j < 9;j++)
printf("%d",map[i][j]);
printf("\n");
}
return 1;
}
for (i = 1 ; i <= 9; i++)
if (!row[x][i] && !col[y][i] && !box[x / 3 * 3 + y / 3][i])
{
map[x][y] = i;
row[x][i] = col[y][i] = box[x / 3 * 3 + y / 3][i] = 1;
p++;
if (DFS(pos[p][0],pos[p][1]))
return 1;
p--;
map[x][y] = 0;
row[x][i] = col[y][i] = box[x / 3 * 3 + y / 3][i] = 0;
}
return 0;
}
int main()
{
int i,j,T;
scanf("%d",&T);
while (T--)
{
p = 0;
memset(row,0,sizeof(row));
memset(col,0,sizeof(col));
memset(box,0,sizeof(box));
for (i = 0; i < 9; i++)
{
for (j = 0; j < 9; j++)
{
scanf("%d",&map[i][j]);
if (map[i][j])
{
row[i][map[i][j]] = 1;
col[j][map[i][j]] = 1;
box[i / 3 * 3 + j / 3][map[i][j]] = 1;
}
else
{
pos[p][0] = i;
pos[p][1] = j;
p++;
}
}
}
n = p;
p = 0;
DFS(pos[0][0],pos[0][1]);
}
return 0;
}