题解 P1784 【数独】
AgrumeStly · · 题解
欢迎回来
欢迎回到TNT BOOM大讲堂!
今天我们来讲
首先明白数独是什么?
懂得跳过
数独(shù dú)是源自18世纪瑞士的一种数学游戏。是一种运用纸、笔进行演算的逻辑游戏。玩家需要根据9×9盘面上的已知数字,推理出所有剩余空格的数字,并满足每一行、每一列、每一个粗线宫(3*3)内的数字均含1-9,不重复 。
数独盘面是个九宫,每一宫又分为九个小格。在这八十一格中给出一定的已知数字和解题条件,利用逻辑和推理,在其他的空格上填入1-9的数字。使1-9每个数字在每一行、每一列和每一宫中都只出现一次,所以又称“九宫格”。
好的,明白了以后,我们想一想,计算机如何实现填数独
首先,我们先明确,这道题是
不好画图,直接那程序写出来了:
int m[10][10] =
{
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 1, 1, 1, 2, 2, 2, 3, 3, 3},
{0, 1, 1, 1, 2, 2, 2, 3, 3, 3},
{0, 1, 1, 1, 2, 2, 2, 3, 3, 3},
{0, 4, 4, 4, 5, 5, 5, 6, 6, 6},
{0, 4, 4, 4, 5, 5, 5, 6, 6, 6},
{0, 4, 4, 4, 5, 5, 5, 6, 6, 6},
{0, 7, 7, 7, 8, 8, 8, 9, 9, 9},
{0, 7, 7, 7, 8, 8, 8, 9, 9, 9},
{0, 7, 7, 7, 8, 8, 8, 9, 9, 9}
};
通过这样的方法,我们就有办法知道某一宫的关系了!
话不多说,上
详细的看注释。
#include<cstdio>
//#include<cstdlib>
using namespace std;
int a[11][11]; //用来存九宫数独的数字
bool flag1[11][11], flag2[11][11], flag3[11][11];
// flag1[i][j]代表第i行,值为j的数是否使用
// flag2[i][j]代表第i列,值为j的数是否使用
// flag3[i][j]代表第i宫,值为j的数是否使用
int m[10][10] =
{
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 1, 1, 1, 2, 2, 2, 3, 3, 3},
{0, 1, 1, 1, 2, 2, 2, 3, 3, 3},
{0, 1, 1, 1, 2, 2, 2, 3, 3, 3},
{0, 4, 4, 4, 5, 5, 5, 6, 6, 6},
{0, 4, 4, 4, 5, 5, 5, 6, 6, 6},
{0, 4, 4, 4, 5, 5, 5, 6, 6, 6},
{0, 7, 7, 7, 8, 8, 8, 9, 9, 9},
{0, 7, 7, 7, 8, 8, 8, 9, 9, 9},
{0, 7, 7, 7, 8, 8, 8, 9, 9, 9}
}; //用来帮助我们定位第几宫;
//将第i宫数字初始化为i,我们就可以根据m的下标直接定位是第几宫
void dfs(int x, int y)
{
if(x == 10 && y == 1) //x表示行,y表示列,10行1列表示数独已经填满
{
for(int i = 1; i <= 9; i++) //数独填满,输出即可
{
for(int j = 1; j <= 9; j++)
printf("%d ", a[i][j]);
puts("");
}
//puts(""),system("pause");
return;
}
int x_new = x, y_new = y + 1; //(x_new,y_new)表示(x,y)的下一个格子的位置
if(y_new == 10) //若列数不满十,则行数不变列数加1;若列数满十,则行数加1,列数变为1
{
x_new++;
y_new = 1;
}
if(a[x][y]) //若(x,y)原来有数字
dfs(x_new, y_new); //递归枚举下一个格子
else //若(x,y)原来没有数字,枚举所有可能:填充1-9
{
for(int i = 1; i <= 9; i++)
{//若第x行 or 第y列 or 第m[x][y]宫 出现值为i的数字,则跳过
if(flag1[x][i] || flag2[y][i] || flag3[m[x][y]][i])
continue;
a[x][y] = i; //x行y列m[x][y]宫都没有出现数字i,则a[x][y]可以填i
flag1[x][i] = flag2[y][i] = flag3[m[x][y]][i] = true;
// a[x][y]可以填i后,x行y列m[x][y]宫都出现了数字i,赋值为true
dfs(x_new, y_new); //递归枚举下一个格子
flag1[x][i] = flag2[y][i] = flag3[m[x][y]][i] = false;
//下一次递归还要用这些标记,所以每次用完要清零
a[x][y] = 0; // 可删来让学生查错,回溯
}
}
}
int main()
{
for(int i = 1; i <= 9; i++)
for(int j = 1; j <= 9; j++)
{
scanf("%d", &a[i][j]);
if(a[i][j] == 0) continue;
//输入的同时根据输入的结果将flag1、flag2、flag3三个数字初始化
flag1[i][a[i][j]] = true;
flag2[j][a[i][j]] = true;
flag3[m[i][j]][a[i][j]] = true;
}
dfs(1, 1);
return 0;
}
好了,本期TNT BOOM 大讲堂就说到这里了。