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这九个数字。

例题:


答案:
 

 

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
ACM暑期集训队练习赛(三)
 

 

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 
  2 #include 
  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<' ';
 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

你可能感兴趣的:(hdu 1426:Sudoku Killer(DFS深搜,进阶题目,求数独的解))