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这九个数字。
例题:
答案:
据说,在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
Recommend
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