洛谷-数独-搜索与回溯

题目描述

数独是根据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 }

 

posted @ 2017-04-15 23:57  Memoryヾノ战心  阅读(772)  评论(0编辑  收藏  举报