洛谷-数独-搜索与回溯
题目描述
数独是根据9×9盘面上的已知数字,推理出所有剩余空格的数字,并满足每一行、每一列、每一个粗线宫内的数字均含1-9,不重复。每一道合格的数独谜题都有且仅有唯一答案,推理方法也以此为基础,任何无解或多解的题目都是不合格的。
芬兰一位数学家号称设计出全球最难的“数独游戏”,并刊登在报纸上,让大家去挑战。
这位数学家说,他相信只有“智慧最顶尖”的人才有可能破解这个“数独之谜”。
据介绍,目前数独游戏的难度的等级有一道五级,一是入门等级,五则比较难。不过这位数学家说,他所设计的数独游戏难度等级是十一,可以说是所以数独游戏中,难度最高的等级他还表示,他目前还没遇到解不出来的数独游戏,因此他认为“最具挑战性”的数独游戏并没有出现。
输入输出格式
输入格式:
一个未填的数独
输出格式:
填好的数独
输入输出样例
输入样例#1:
8 0 0 0 0 0 0 0 0 0 0 3 6 0 0 0 0 0 0 7 0 0 9 0 2 0 0 0 5 0 0 0 7 0 0 0 0 0 0 0 4 5 7 0 0 0 0 0 1 0 0 0 3 0 0 0 1 0 0 0 0 6 8 0 0 8 5 0 0 0 1 0 0 9 0 0 0 0 4 0 0
输出样例#1:
8 1 2 7 5 3 6 4 9 9 4 3 6 8 2 1 7 5 6 7 5 4 9 1 2 8 3 1 5 4 2 3 7 8 9 6 3 6 9 8 4 5 7 2 1 2 8 7 1 6 9 5 3 4 5 2 1 9 7 4 3 6 8 4 3 8 5 2 6 9 1 7 7 9 6 3 1 8 4 5 2
说明
你猜,你猜,你猜猜猜
猜不出来吧,我不告诉你~~~
思路:这题就是简单的搜索题目,首先我们要明确搜索什么:首先我们可以把从1到9中的每一个数字放进去试试看,如果这个数字在当前九宫格内未出现过并且在当前行当前列未出现,就可以放进去,如果出现过了,就回溯一下嗯。
我们对于“这个数字有没有在当前行当前列中出现过”这个判断,我是用并查集的方法来做的,比如第一行有一个数字8,在当前行内出现了,我们就把x[1][8]标记为1,这样我们下次判断8是否在这行中出现时,只需判断x[1][8]是否为1就行了,同理对于列也是一样。
在这里可以用flag记录当前放置数字的步数,每次放一个就flag++,这样当flag=9*9=81时,说明已经放满了,输出即可。
代码如下:
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <stdlib.h> 4 /*==============================*///一些全局变量 5 int flag=0; 6 int num[9][9]={0};//原始数据数组 7 int x[9][9]={0};//标记这一行是否有重复的 8 int y[9][9]={0};//标记这一列是否有重复的 9 /*==============================*/ 10 int inspect(int i,int j,int dj)//检查当前这个数字是否在九宫格中有重复,传入的是当前数字的坐标i,j,和这个数dj也就是传过来的i值 11 { 12 i=i/3*3; 13 j=j/3*3; 14 for(int ii=0;ii<3;ii++) 15 { 16 for(int jj=0;jj<3;jj++) 17 { 18 if(num[i+ii][j+jj]==dj)//在这个九宫格出现过,返回非 19 { 20 return 0; 21 } 22 } 23 } 24 return 1;//否则是真 25 } 26 void shuchu()//输出这个数组 27 { 28 for(int i=0;i<9;i++) 29 { 30 for(int j=0;j<9;j++) 31 { 32 printf("%d ",num[i][j]); 33 } 34 printf("\n"); 35 } 36 } 37 38 void DFS(int flag) 39 { 40 if(flag==9*9)//如果所有空都被填满,传入输出结果函数,输出结果 41 { 42 shuchu(); 43 exit(0);//毁灭程序 44 } 45 else 46 { 47 if(num[flag/9][flag%9]!=0)//如果这个位置已经填好数字了,直接跳过即可 48 { 49 DFS(flag+1);//搜索下一个 50 } 51 else//如果是空位,放数字 52 { 53 for(int i=1;i<=9;i++) 54 { 55 if((x[flag/9][i-1]==0)&&(y[flag%9][i-1]==0)&&(inspect(flag/9,flag%9,i)))//这个数字在当前行和列没有重复并且在九宫格中也没有重复哦~ 我就放上去好了 56 { 57 num[flag/9][flag%9]=i;//把当前i放入数组 58 x[flag/9][i-1]=1;//在当前行已经使用过了 59 y[flag%9][i-1]=1;//在当前列已经使用过了 60 DFS(flag+1);//搜索下一个 61 /*===========================*///还原现场,回溯 62 num[flag/9][flag%9]=0; 63 x[flag/9][i-1]=0; 64 y[flag%9][i-1]=0; 65 /*===========================*/ 66 } 67 } 68 } 69 } 70 71 } 72 int main() 73 { 74 int i,j; 75 for(i=0;i<9;i++) 76 { 77 for(j=0;j<9;j++) 78 { 79 scanf("%d",&num[i][j]); 80 /*==================================*/ 81 if(num[i][j]) 82 { 83 x[i][num[i][j]-1]=1;//标记这个数字在当前行已经被使用过 84 y[j][num[i][j]-1]=1;//标记这个数字在当前行已经被使用过 85 } 86 /*==================================*/ 87 } 88 } 89 DFS(0);//调用深度优先搜索 90 return 0; 91 }
我不怕千万人阻挡,只怕自己投降…