题目(填空)
思路
拿到题首先想到的是人做?不可能的太玄学了,除非你真的很会数独。
那就暴力——搜索吧,也就是满足一个数就填进格子里去,然后进入下一层,不满足的话就退回来,把填进去的数取掉。
当然其中最主要的就是符合数独的规则:
1、同行无相同数字;
2、同列无相同数字;
3、9个3*3九宫格内无相同数字。
那么如何满足这三个规则呢?一共九个数 1~9。
1、针对第一个规则,建立布尔类型二维数组 row[10][10] 进行行标记(初始全为0)
如: row[5][6]=1 就代表第5行填入数字,且为6
2、针对第二个规则,建立布尔类型二维数组 col[10][10] 进行列标记(初始全为0)
如: col[5][6]=1 就代表第5列填入数字,且为6
3、针对第三个规则,建立布尔类型三维数组 mat[3][3][10] 进行3*3九宫格标记(初始全为0),为何前两个数字为3 ?因为9行9列如果以9宫格为行列的话就是3行3列
如: mat[0][0][5]=1 就代表第1行第1列九宫格填入数字,且为5
最后我们只需让计算机暴力跑图,只要这三个数组中有为0的就说明有数字没填入网格。
代码
#include <iostream>
#include <cstdio>
#include <cstring>
#define M 10
using namespace std;
struct point //存未填空的行列坐标
{
int x, y;
} p[100];
int flag;
bool row[M][M]; //行标记
bool col[M][M]; //列标记
bool mat[3][3][M]; //九宫格标记
int np = 0; //记录图中没填入数字的个数
int Map[M][M]= {
{0,2,6,0,0,0,0,0,0},
{0,0,0,5,0,2,0,0,4},
{0,0,0,1,0,0,0,0,7},
{0,3,0,0,2,0,1,8,0},
{0,0,0,3,0,9,0,0,0},
{0,5,4,0,1,0,0,7,0},
{5,0,0,0,0,1,0,0,0},
{6,0,0,9,0,7,0,0,0},
{0,0,0,0,0,0,7,5,0}}; //要跑的图
void dfs(int n)
{
if(flag) //flag==1,图已填满
return ;
if(n==-1&&flag==0)
//每次进入dfs,未填空数n要减1,p[0]中也有记录为填空的行列坐标,则最后一次进入dfs时n==-1
//当n==-1时,说明图已经填完,flag==0,说明还未输出
{
for(int i=0;i<9;i++)
{
for(int j=0;j<8;j++)
{
printf("%d ",Map[i][j]);
}
printf("%d\n",Map[i][8]);
}
flag=1; //已经输出,且图满
}
for(int i=1;i<=9&&flag==0;i++) //i为要填写的数字的可能性1~9
{
int x=p[n].x; //第x行
int y=p[n].y; //第y列
if(!row[x][i]&&!col[y][i]&&!mat[x/3][y/3][i]) //三个约束条件
{
row[x][i]=col[y][i]=mat[x/3][y/3][i]=1; //满足至1
Map[x][y]=i; //填入该数字
dfs(n-1); //进入下一个空
row[x][i]=col[y][i]=mat[x/3][y/3][i]=0; //不满足恢复标记0
Map[x][y]=0; //取出该数字
}
}
}
int main()
{
flag=0; //图中若有没填写的数字为0,填满为1
memset(row,0,sizeof(row));
memset(col,0,sizeof(col));
memset(mat,0,sizeof(mat));
for(int i=0;i<9;i++)
{
for(int j=0;j<9;j++)
{
int num=Map[i][j];
if(num) //若数字不为0,则说明该空已填写数字
{
row[i][num]=col[j][num]=mat[i/3][j/3][num]=1;
//则该行该列该九宫格至1
}
else //若该数字为0,则说明该空没有填写数字
{
p[np].x=i;
p[np++].y=j;
//记录该空的行列坐标
}
}
}
dfs(np-1); //np-1为未填写数字的空数,之前np++了哦
return 0;
}