hdu 1426:Sudoku Killer(DFS深搜,进阶题目,求数独的解)

Sudoku Killer

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 3723    Accepted Submission(s): 1170


Problem Description
自从2006年3月10日至11日的首届数独世界锦标赛以后,数独这项游戏越来越受到人们的喜爱和重视。
据说,在2008北京奥运会上,会将数独列为一个单独的项目进行比赛,冠军将有可能获得的一份巨大的奖品———HDU免费七日游外加lcy亲笔签名以及同hdu acm team合影留念的机会。
所以全球人民前仆后继,为了奖品日夜训练茶饭不思。当然也包括初学者linle,不过他太笨了又没有多少耐性,只能做做最最基本的数独题,不过他还是想得到那些奖品,你能帮帮他吗?你只要把答案告诉他就可以,不用教他是怎么做的。

数独游戏的规则是这样的:在一个9x9的方格中,你需要把数字1-9填写到空格当中,并且使方格的每一行和每一列中都包含1-9这九个数字。同时还要保证,空格中用粗线划分成9个3x3的方格也同时包含1-9这九个数字。比如有这样一个题,大家可以仔细观察一下,在这里面每行、每列,以及每个3x3的方格都包含1-9这九个数字。

例题:
hdu 1426:Sudoku Killer(DFS深搜,进阶题目,求数独的解)

答案:
hdu 1426:Sudoku Killer(DFS深搜,进阶题目,求数独的解)
 

 

Input
本题包含多组测试,每组之间由一个空行隔开。每组测试会给你一个 9*9 的矩阵,同一行相邻的两个元素用一个空格分开。其中1-9代表该位置的已经填好的数,问号(?)表示需要你填的数。
 

 

Output
对于每组测试,请输出它的解,同一行相邻的两个数用一个空格分开。两组解之间要一个空行。
对于每组测试数据保证它有且只有一个解。
 

 

Sample Input
7 1 2 ? 6 ? 3 5 8

? 6 5 2 ? 7 1 ? 4

? ? 8 5 1 3 6 7 2

9 2 4 ? 5 6 ? 3 7

5 ? 6 ? ? ? 2 4 1

1 ? 3 7 2 ? 9 ? 5

? ? 1 9 7 5 4 8 6

6 ? 7 8 3 ? 5 1 9

8 5 9 ? 4 ? ? 2 3

 

 

 

Sample Output
7 1 2 4 6 9 3 5 8

3 6 5 2 8 7 1 9 4

4 9 8 5 1 3 6 7 2

9 2 4 1 5 6 8 3 7

5 7 6 3 9 8 2 4 1

1 8 3 7 2 4 9 6 5

2 3 1 9 7 5 4 8 6

6 4 7 8 3 2 5 1 9

8 5 9 6 4 1 7 2 3

 

 

 

Author
linle
 

 

Source
 

 

Recommend
LL   |   We have carefully selected several similar problems for you:   1258  1045  2614  1067  1312 
 
  DFS搜索,进阶题目
  题意是给你多个数独题目,让你输出它们的答案。
  思路是递归确定每一个‘?’的位置的值,直到所有‘?’都被确定。先将原字符数组转换为整型数组,‘?’由数字0代替,然后每一次层递归找到第一个0的位置,如果找到了,找出当前位置所有可以放置的数字,依次尝试,每次假设把这个数放在当前位置,然后再确认下一个0位置的数字,直到数组中找不到0,即是正确结果(递归出口)。
  注意输入格式,要求输入的每组数据之间有一个空行,可以先单独输入第一组数据,后面的数据都是先读取空行,再读取数据。
  题目给的测试数据很弱,献上一组我的测试数据,如果你总是WA可以试试:
? 5 ? 4 ? 8 ? ? 2

? ? 1 ? ? 5 7 3 ?

? 6 2 ? ? 7 ? ? 9

? ? 8 ? 6 3 2 ? 7

3 ? ? 1 ? ? ? ? 6

5 ? 6 2 ? ? 9 ? ?

4 ? ? 7 ? ? 8 2 ?

? 1 7 8 ? ? 3 ? ?

2 ? ? 9 ? 1 ? 7 ?

  答案

7 5 3 4 9 8 1 6 2

9 4 1 6 2 5 7 3 8

8 6 2 3 1 7 4 5 9

1 9 8 5 6 3 2 4 7

3 2 4 1 7 9 5 8 6

5 7 6 2 8 4 9 1 3

4 3 9 7 5 6 8 2 1

6 1 7 8 4 2 3 9 5

2 8 5 9 3 1 6 7 4

  注意如果这一步的所有情况都判定失败,返回上一层递归的时候不要忘了将当前位置还原为“?”的状态,否则会影响以后的递归。

  代码量比别人长了一些,速度也达到了400MS左右,但好在关键地方都做了注释,代码还算好懂,看官们有改进意见可以跟我提。

  不费话了,上代码

 1 #include <stdio.h>

 2 #include <iostream>

 3 using namespace std;  4 void putoutint(int b[9][9])    //输出整型二维数组

 5 {  6     int i,j;  7     for(i=0;i<9;i++){  8         for(j=0;j<9;j++)  9             if(j!=8)  10                 cout<<b[i][j]<<' ';  11             else

 12                 cout<<b[i][j];  13         cout<<endl;  14  }  15 }  16 void char2int(char a[9][20],int b[9][9])    //字符二维数组向整型二维数组转换

 17 {  18     int i,j;  19     for(i=0;i<9;i++)  20         for(j=0;j<18;j++)  21             if(a[i][j]=='?')  22                 b[i][j/2] = 0;  23             else if('1'<=a[i][j] && a[i][j]<='9')  24                 b[i][j/2] = a[i][j]-'0';  25 }  26 bool judge(int curx,int cury,int num,const int b[9][9])  27 {  28     int i,j;  29     //查找一横行

 30     for(i=0;i<9;i++)    //将这一行出现的数字全部设为不可填

 31         if(i!=cury && b[curx][i]==num)  32             return true;  33     //查找一竖列

 34     for(i=0;i<9;i++)    //将这一行出现的数字全部设为不可填

 35         if(i!=curx && b[i][cury]==num)  36             return true;  37     //查找当前九宫格

 38     int x,y;  39     x = curx/3*3;  40     y = cury/3*3;  41     for(i=0;i<3;i++)  42         for(j=0;j<3;j++)  43             if(x+i!=curx && y+j!=cury && b[x+i][y+j]==num)  44                 return true;  45     return false;  46 }  47 bool dfs(int b[9][9])  48 {  49     //找到当前第一个'?'位置。如果没有找到,表示所有位置都已填上,即为正确结果,递归结束

 50     int i,j;  51     for(i=0;i<9;i++)  52         for(j=0;j<9;j++)  53             if(b[i][j]==0)    //找'?'的位置

 54                 goto label;  55  label:  56     if(i>=9 && j>=9)    //找到正确结果了,递归结束

 57         return true;  58     //记录坐标

 59     int curx = i,cury = j;  60     //确定该位置的可以填的数字

 61     bool temp[10];    //记录哪些数字可以填

 62     int num=0;    //记录当前位置可以填的数字的个数

 63     for(i=1;i<=9;i++)  64         if(judge(curx,cury,i,b))    //判断这个位置可不可以放这个数字

 65             temp[i] = false;  66         else {  67             temp[i] = true;  68             num++;  69  }  70     if(num==0)  71         return false;  72     //确定下一个位置

 73     for(i=1;i<=9;i++)  74         if(temp[i]){  75             //这个数在这个位置可以填

 76             if(judge(curx,cury,i,b))  77                 continue;  78             b[curx][cury] = i;  79             if(dfs(b))  80                 return true;  81  }  82     b[curx][cury] = 0;    //这句千万别忘了写,就是这一步不能走的记得还原为0

 83     return false;  84 }  85 int main()  86 {  87     char a[9][20];  88     int b[9][9];  89     int i;  90     for(i=0;i<9;i++)  91         cin.getline(a[i],20,'\n');  92     char2int(a,b);    //char数组转换为int数组

 93     if(dfs(b))    //产生结果

 94         putoutint(b);    //输出数组内容

 95 

 96     while(cin.getline(a[0],20,'\n')){    //读取空行,或者到文件尾

 97         cout<<endl;  98         char a[9][20];  99         int b[9][9]; 100         int i; 101         for(i=0;i<9;i++) 102             cin.getline(a[i],20,'\n'); 103         char2int(a,b);    //char数组转换为int数组

104         if(dfs(b))    //产生结果

105             putoutint(b);    //输出数组内容

106  } 107     return 0; 108 }

 

Freecode : www.cnblogs.com/yym2013

你可能感兴趣的:(sudo)