【问题描述】
数独是一个风靡全球的解谜游戏。它的规则如下:
在一个9*9的方格中,有一些位置上已经填有数字。你需要把1~9填写到空格当中,并且使用方格的每一行,每一列中包含1~9这九个数字。同时还要保证,空格中用粗线划分的9个3*3的方格也同时包含1~9这九个数字。下图是一个数独的样例:
现在给出一个数独,请你找出他的解。
【输入格式】
输入数据一共9行,每行有9个字符。
输入数据描述了一个待解决的数独,其中,“?”表示数独中的空缺。
我们的输入数据总保证有唯一解。
【输出格式】
输出一共9行,每行9个数字,表示你的答案。
【输入样例】
5????7??6
?6????5?4
?834?????
???182?4?
??1???9??
?7?369???
?????543?
1?5????9?
7??2????1
【输出样例】
514927386
967831524
283456179
659182743
321574968
478369215
892615437
135748692
746293851
【数据范围】
输入的数据保证答案唯一。
【问题分析】
一道很经典的回溯题,如果采用枚举铁定超时,因此采用回溯法解决此类向表中填数字判断是否合法的问题。
1.分步:共9行9列(x,y)
2.每步:每一个格子都有1~9个选项,弹药注意约束
3.约束:每行每列每个九宫格不许相同
4.选择后若此行未填完,则填下一列;否则填下一行第一列
5.求解:当填完最后一个格子后即可输出
【细节分析】
1.约束条件的写法
定义三个bool函数
bool ok=0,ge[4][4][10],h[10][10],l[10][10];
ge表示九个小九宫格的情况,h表示每一行的情况,l表示每一列的情况
tip:小九宫格的大坐标为(x/3,y/3)
2.预处理
每一行采用字符串输入
输入后应将已经填的的数放入要填的表中
且将其标记为true
3.每次找到合法的数字进入下一层后,除了要解除三个标记数组的标记,还需将已经填入表的数字擦除(因为这也是判断是否填数的条件!!)
4.由题意,因为所给数据只有一个解,所以可以定义一个ok=0,只要找到了一组解后ok=1;
只要当ok=1后即可跳出递归——>避免不必要的重复~~~
#include<cstdio>
#include<iostream>
#include<vector>
#include<queue>
#include<cmath>
#include<algorithm>
#include<cstring>
using namespace std;
bool ok=0,ge[4][4][10],h[10][10],l[10][10];//ge表示九个小九宫格的情况,h表示每一行的情况,l表示每一列的情况
int map[11][10];
char ch[10];
void input_()
{
for(int i=0;i<9;i++)
{
scanf("%s",ch);
for(int j=0;j<9;j++)
if(ch[j]!='?')
{
map[i][j]=ch[j]-'0';
ge[i/3][j/3][map[i][j]]=l[j][map[i][j]]=h[i][map[i][j]]=1;
}
}
}
void output_()
{
for(int i=0;i<9;i++)
{
for(int j=0;j<9;j++)
printf("%d",map[i][j]);
printf("\n");
}
}
bool judge(int i,int x,int y)
{
if(ge[x/3][y/3][i]==0&&
l[y][i]==0&&
h[x][i]==0)return 1;
return 0;
}
void run(int x,int y)//x表示行y表示列
{
if(x==9)
{
output_();
ok=1;
return;
}
if(map[x][y]!=-1)
{
if(y==8)run(x+1,0);
else run(x,y+1);
return;
}
for(int i=1;i<=9;i++)if(judge(i,x,y)==1)//if(h[x][i]==false && l[y][i]==false && ge[x/3][y/3][i]==false)////每一行枚举1~9
{
map[x][y]=i;
ge[x/3][y/3][i]=l[y][i]=h[x][i]=1;
if(y==8)run(x+1,0);
else run(x,y+1);
if(ok)return;//避免多余的分枝
ge[x/3][y/3][i]=l[y][i]=h[x][i]=0;
map[x][y]=-1;//需将已填的数字也擦除!!
}
}
int main()
{
//freopen("in.txt","r",stdin);
// freopen("out.txt","w",stdout);
memset(map,-1,sizeof(map));
input_();
run(0,0);
return 0;
}
Written by Mr.Shadow from CQYZ