【原创】转载请注明出处。 【浙江大学 程序设计专题】
使用方法:按提示输入方式为9*9的矩阵,0表示未知数。
为解决这一问题,我们也尝试了两种方法,准确的说,是第一种方法太慢了,我们对它进行了优化。
方法一:
用最朴素的方法逐一枚举每一个格子,在某一个格子不能填入任何数字时回溯。
这个方法写法相对简单,但对于一些难以求解的情况,程序会非常慢,最慢的甚至无法在3秒内得出答案。如果每一个情况需要三秒钟来求解,那么要批量求解数独可能需要等好几分钟。
尽管我们将编译器的优化选项开到最高,一些情况仍需要1秒左右。
方法二:
模拟手算,当给定一道题目时,首先确定每个格子可以填那些数字,每次优先选择可选数字最少的格子。
此方法对于大多数数据能在0.1秒内求解。
方法一样例解释:绿色数字表示有多重可能的格子,红色数字表示唯一可能的格子,红色填充的格子表示无法填入数字。
方法二样例:
方法一代码:
1 #include <stdio.h> 2 #include <string.h> 3 #include <stdlib.h> 4 #include <time.h> 5 #include "prnt_sudoku.h" 6 7 /*Sudoku save in array Map, index counts from 0.*/ 8 int Map[9][9],cnt; 9 /*R<->Row B<->Block C<->Column*/ 10 int R[11][11],B[11][11],C[11][11]; 11 /*characters on the left and right of output-numbers.*/ 12 /*this will make user know which numbers are given at first.*/ 13 char C1[9][9],C2[9][9]; 14 15 int Dfs(const int x,const int y) 16 { 17 if(x==9) 18 { 19 printf("\n\n\tSolution #%d: \n\n",++cnt); 20 Print(Map,C1,C2); 21 /*when there are too many solutions return 1*/ 22 /*and the whole Search algorithm will stop*/ 23 if(cnt==5000) return 1; 24 return 0; 25 } 26 27 if(Map[x][y]) { return Dfs(x+(y+1)/9,(y+1)%9); } 28 /*if (x,y) is known, then fill the next one.*/ 29 30 int i; 31 for(i=1;i<=9;++i) 32 { 33 /*Check if setting i in blank(x,y) is proper.*/ 34 if(R[x][i] || C[y][i] || B[x/3*3+y/3][i])continue; 35 36 /*update arrays*/ 37 Map[x][y]=i; 38 R[x][i]=1; C[y][i]=1; B[x/3*3+y/3][i]=1; 39 40 if(Dfs(x+(y+1)/9,(y+1)%9)) return 1; 41 /*this expression will fill blanks from the left-up one to */ 42 /* the right-down one automaticly.*/ 43 44 /*undo*/ 45 R[x][i]=0; C[y][i]=0; B[x/3*3+y/3][i]=0; 46 Map[x][y]=0; 47 } 48 return 0; 49 } 50 51 52 int main() 53 { 54 int op,T=0; 55 system("cls"); 56 printf("Choose input/output way(1.Keyboard/2.File): "); 57 while(1)/*until receiving an expected input.*/ 58 { 59 scanf("%d",&op); 60 if(op==1)break; 61 if(op==2)/*file input*/ 62 { 63 char File_Name[110]; 64 printf("Please input File_Name: "); 65 scanf("%s",File_Name); 66 printf("\n\tResult Will Save to Result.txt\n\n"); 67 printf("\tCalculating....\n\n"); 68 freopen(File_Name,"r",stdin); 69 freopen("Result.txt","w",stdout);/*answer file is "Result.txt" */ 70 break; 71 } 72 } 73 74 while(1)/*Support multi-set test, read to EOF.*/ 75 { 76 /*Initialize*/ 77 memset(R,0,sizeof(R)); 78 memset(C,0,sizeof(C)); 79 memset(B,0,sizeof(B)); 80 memset(Map,0,sizeof(Map)); 81 cnt=0; 82 if(op==1)printf("Please Input 9*9 matrix(0 for space):\n"); 83 int i,j,data; 84 /*Read until EOF*/ 85 for(i=0;i<9;++i) for(j=0;j<9;++j) 86 { 87 if(!(~scanf("%1d",&data))) 88 { 89 if(op==1)system("pause"); 90 fclose(stdin); 91 return 0; 92 } 93 Map[i][j]=data; 94 R[i][data]++; 95 C[j][data]++; 96 B[i/3*3+j/3][data]++; 97 } 98 99 printf("Test Case #%d: ",++T); 100 int f=0;/*Check if the sudoku is valid.*/ 101 for(i=0;i<9;++i) for(j=1;j<=9;++j) 102 if(R[i][j]>1|| C[i][j]>1 || B[i][j]>1) f=1; 103 if(f)/*Invalid input*/ 104 { 105 fprintf(stderr,"\n\t\tError in Test Case #%d: ",T); 106 fprintf(stderr,"Invalid Input.\n"); 107 printf("\n\n\tFiled: No Solution Found!\n\n"); 108 continue; 109 } 110 111 /*Mark the known grids.*/ 112 for(i=0;i<9;++i) for(j=0;j<9;++j) 113 if(Map[i][j])C1[i][j]='[',C2[i][j]=']'; 114 else C1[i][j]=C2[i][j]=' '; 115 116 int t1=clock();/*Timer*/ 117 if(Dfs(0,0)) 118 /*In case of costing too much time and disk storage,*/ 119 /*Dfs(int,int) will find at most 5000 kinds of solution.*/ 120 { 121 fprintf(stderr,"\n\t\tError in Test Case #%d: ",T); 122 fprintf(stderr,"Too much solution! Calculation has broken.\n"); 123 } 124 125 /*output the time*/ 126 if(cnt==0) printf("\n\n\tFiled: No Solution Found!\n\n"); 127 else printf("\n\n\t%d Solution Found In %ldms.\n\n",cnt,1000*(clock()-t1)/CLOCKS_PER_SEC); 128 } 129 130 return 0; 131 }