• [ C语言版 ] 数独计算器 [ 搜索剪枝法 ]


    【原创】转载请注明出处。 【浙江大学 程序设计专题】

    使用方法:按提示输入方式为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("
    
    	Solution #%d:  
    
    ",++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("
    	Result Will Save to Result.txt
    
    ");
     67             printf("	Calculating....
    
    ");
     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):
    ");
     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,"
    		Error in Test Case #%d: ",T);
    106             fprintf(stderr,"Invalid Input.
    ");
    107             printf("
    
    	Filed: No Solution Found!
    
    ");
    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,"
    		Error in Test Case #%d: ",T);
    122             fprintf(stderr,"Too much solution! Calculation has broken.
    ");
    123         }
    124 
    125         /*output the time*/
    126         if(cnt==0) printf("
    
    	Filed: No Solution Found!
    
    ");
    127         else printf("
    
    	%d Solution Found In %ldms.
    
    ",cnt,1000*(clock()-t1)/CLOCKS_PER_SEC);
    128     }
    129 
    130     return 0;
    131 }
    View Code

    方法二代码:

      1 #include <stdio.h>
      2 #include <string.h>
      3 #include <stdlib.h>
      4 #include <time.h>
      5 #include "prnt_sudoku.h"
      6 
      7 struct PII { int x,y; };
      8 
      9 /*Sudoku save in array Map, index counts from 0.*/
     10 int    Map[9][9],cnt;
     11 /*F[i][j][k] refers to that, in grid (i,j), number k is used if F[i][j][k]!=0*/
     12 int    F[9][9][10];
     13 /*characters on the left and right of output-numbers.*/
     14 /*this will make user know which numbers are given at first.*/
     15 char    C1[9][9],C2[9][9];
     16 
     17 /*Mark Row x and Column y,and the 3*3 grid that number 'data' has been used.*/
     18 void    Update(const int x,const int y,const int data)
     19 {
     20     int i,px=x/3,py=y/3;
     21     for(i=0;i<9;++i)
     22     {
     23         F[x][i][data]++;/*Row*/
     24         F[i][y][data]++;/*Column*/
     25         F[px*3+i/3][py*3+i%3][data]++;/*Block*/
     26     }
     27 }
     28 
     29 /*Undo 'Update'.*/
     30 void    Undo_update(const int x,const int y,const int data)
     31 {
     32     int i,px=x/3,py=y/3;
     33     for(i=0;i<9;++i)
     34     {
     35         F[x][i][data]--;/*Row*/
     36         F[i][y][data]--;/*Column*/
     37         F[px*3+i/3][py*3+i%3][data]--;/*Block*/
     38     }
     39 }
     40 
     41 /*Returns a pair of int (x,y) referring to the next grid should fill.*/ 
     42 struct PII Get_next()
     43 {
     44     int i,j,k,Min=0x7fffffff;
     45     struct PII pos;
     46     for(i=0;i<9;++i)
     47         for(j=0;j<9;++j)
     48         {
     49             if(Map[i][j])continue;
     50             int cc=0;/*to count how many numbers are not used*/
     51             for(k=1;k<=9;++k)
     52                 if(!F[i][j][k])cc++;
     53             if(cc==0) { pos.x=-1; return pos; }
     54             if(cc<Min)Min=cc,pos.x=i,pos.y=j;
     55             /*Choose the grid which has least numbers can use.*/
     56         }
     57     if(Min!=0x7fffffff) return pos;
     58     pos.x=-1; return pos;/*No grids can fill in*/
     59 }
     60 
     61 int    Dfs(const int rest)
     62 {
     63     if(rest==0)
     64     {
     65         printf("
    
    	Solution #%d:  
    
    ",++cnt);
     66         Print(Map,C1,C2);
     67         /*too many solutions.*/
     68         if(cnt==5000) return 1;
     69         return 0;
     70     }
     71     struct PII pos=Get_next();
     72     if(pos.x==-1) return 0;
     73     int i,list[11],top=0;
     74     /*find numbers not used, and save then in 'list'.*/
     75     for(i=1;i<=9;++i)
     76         if(!F[pos.x][pos.y][i]) list[top++]=i;
     77     for(i=0;i<top;++i)
     78     {
     79         /*Mark that number 'i' has been used*/
     80         Map[pos.x][pos.y]=list[i];
     81         Update(pos.x,pos.y,list[i]);
     82         
     83         if(Dfs(rest-1)) return 1;
     84         /*if Dfs retruns 1, there would be too many solutions*/
     85         /*stop searching and return*/
     86         
     87         /*Undo*/
     88         Undo_update(pos.x,pos.y,list[i]);
     89         Map[pos.x][pos.y]=0;
     90     }
     91     return 0;
     92 }
     93 
     94 int main()
     95 {
     96     int op,T=0;
     97     system("cls");
     98     printf("Choose input/output way(1.Keyboard/2.File):  ");
     99     while(1)/*until receiving an expected input.*/
    100     {
    101         scanf("%d",&op);
    102         if(op==1)break;
    103         if(op==2)
    104         {
    105             char File_Name[110];
    106             printf("Please input File_Name:  ");
    107             scanf("%s",File_Name);
    108             printf("
    	Result Will Save to Result.txt
    
    ");
    109             printf("	Calculating....
    
    ");
    110             freopen(File_Name,"r",stdin);
    111             freopen("Result.txt","w",stdout);
    112             break;
    113         }
    114     }
    115 
    116     while(1)/*Support multi-set test, read to EOF.*/
    117     {
    118         memset(F,0,sizeof(F));
    119         memset(Map,0,sizeof(Map));
    120         cnt=0;
    121         if(op==1)printf("Please Input 9*9 matrix(0 for space):
    ");
    122         int i,j,data;
    123         
    124         /*Read until EOF*/
    125         for(i=0;i<9;++i) for(j=0;j<9;++j)
    126         {
    127             if(!(~scanf("%1d",&data)))
    128             /*Only ~(-1)==0 while EOF==-1*/
    129             {
    130                 if(op==1)system("pause");
    131                 fclose(stdin);
    132                 return 0;
    133             }
    134             Map[i][j]=data;
    135         }
    136 
    137         int rest=81;/*Update array 'F'. */
    138         for(i=0;i<9;++i) for(j=0;j<9;++j)
    139             if(Map[i][j]) Update(i,j,Map[i][j]),rest--;
    140 
    141         printf("Test Case #%d: ",++T);
    142 
    143         /*Check if the input is corret.*/
    144         int f=0,k;
    145         for(i=0;i<9;++i)
    146         {
    147             for(j=0;j<9;++j)
    148             {
    149                 if(Map[i][j] && F[i][j][Map[i][j]]>3) { f=1; break; }
    150                 if(Map[i][j])continue;
    151                 int cc=0;/*Count the numbers can use in (i,j)*/
    152                 for(k=1;k<=9;++k)
    153                     if(!F[i][j][k])cc++;
    154                 if(cc==0) { f=1; break; }
    155             }
    156             if(j!=9) break;
    157         }
    158 
    159         /*Input error*/
    160         if(f)
    161         {
    162             fprintf(stderr,"
    		Error in Test Case #%d: ",T);
    163             fprintf(stderr,"Invalid Input.
    ");
    164             printf("
    
    	Filed: No Solution Found!
    
    ");
    165             continue;
    166         }
    167 
    168         /*if a number is known, it will be output as [x]*/
    169         /*otherwise, there will not be the square brackets, spaces instead.*/
    170         for(i=0;i<9;++i)
    171             for(j=0;j<9;++j)
    172                 if(Map[i][j])C1[i][j]='[',C2[i][j]=']';
    173                 else C1[i][j]=C2[i][j]=' ';
    174 
    175         int t1=clock();/*Timer*/
    176         if(Dfs(rest))
    177             /*In case of costing too much time and disk storage,*/
    178             /*Dfs(int,int) will find at most 5000 kinds of solution.*/
    179         {
    180             fprintf(stderr,"
    		Error in Test Case #%d: ",T);
    181             fprintf(stderr,"Too much solution! Calculation has broken.
    ");
    182         }
    183 
    184         if(cnt==0) printf("
    
    	Filed: No Solution Found!
    
    ");
    185         else printf("
    
    	%d Solution Found In %ldms.
    
    ",cnt,1000*(clock()-t1)/CLOCKS_PER_SEC);
    186     }
    187 
    188     return 0;
    189 }
    View Code

    输出函数print_sudoku.h(上面两篇代码公用):

     1 /*
     2     *This head defines the function to print a Sudoku by a 9*9 array
     3     *Map[9][9] is the munber matrix,C1,C2 are the characters to print on the left and
     4     *  right side of the numbers.
     5 */
     6 #include <stdio.h>
     7 /*Function for printing the Sudoku table.*/
     8 void    Print(int Map[9][9],char C1[9][9],char C2[9][9])
     9 {
    10     printf("	  || A | B | C || D | E | F || G | H | I ||
    ");
    11     printf("	==#########################################
    ");
    12     printf("	1-##%c%d%c|%c%d%c|%c%d%c||%c%d%c|%c%d%c|%c%d%c||%c%d%c|%c%d%c|%c%d%c##
    ",
    13         C1[0][0], Map[0][0], C2[0][0], C1[0][1], Map[0][1], C2[0][1],
    14         C1[0][2], Map[0][2], C2[0][2], C1[0][3], Map[0][3], C2[0][3],
    15         C1[0][4], Map[0][4], C2[0][4], C1[0][5], Map[0][5], C2[0][5],
    16         C1[0][6], Map[0][6], C2[0][6], C1[0][7], Map[0][7], C2[0][7],
    17         C1[0][8], Map[0][8], C2[0][8]);
    18     printf("	--##---+---+---||---+---+---||---+---+---##
    ");
    19     printf("	2-##%c%d%c|%c%d%c|%c%d%c||%c%d%c|%c%d%c|%c%d%c||%c%d%c|%c%d%c|%c%d%c##
    ",
    20         C1[1][0], Map[1][0], C2[1][0], C1[1][1], Map[1][1], C2[1][1],
    21         C1[1][2], Map[1][2], C2[1][2], C1[1][3], Map[1][3], C2[1][3],
    22         C1[1][4], Map[1][4], C2[1][4], C1[1][5], Map[1][5], C2[1][5],
    23         C1[1][6], Map[1][6], C2[1][6], C1[1][7], Map[1][7], C2[1][7],
    24         C1[1][8], Map[1][8], C2[1][8]);
    25     printf("	--##---+---+---||---+---+---||---+---+---##
    ");
    26     printf("	3-##%c%d%c|%c%d%c|%c%d%c||%c%d%c|%c%d%c|%c%d%c||%c%d%c|%c%d%c|%c%d%c##
    ",
    27         C1[2][0], Map[2][0], C2[2][0], C1[2][1], Map[2][1], C2[2][1],
    28         C1[2][2], Map[2][2], C2[2][2], C1[2][3], Map[2][3], C2[2][3],
    29         C1[2][4], Map[2][4], C2[2][4], C1[2][5], Map[2][5], C2[2][5],
    30         C1[2][6], Map[2][6], C2[2][6], C1[2][7], Map[2][7], C2[2][7],
    31         C1[2][8], Map[2][8], C2[2][8]);
    32     printf("	==##===========++===========++===========##
    ");
    33     printf("	4-##%c%d%c|%c%d%c|%c%d%c||%c%d%c|%c%d%c|%c%d%c||%c%d%c|%c%d%c|%c%d%c##
    ",
    34         C1[3][0], Map[3][0], C2[3][0], C1[3][1], Map[3][1], C2[3][1],
    35         C1[3][2], Map[3][2], C2[3][2], C1[3][3], Map[3][3], C2[3][3],
    36         C1[3][4], Map[3][4], C2[3][4], C1[3][5], Map[3][5], C2[3][5],
    37         C1[3][6], Map[3][6], C2[3][6], C1[3][7], Map[3][7], C2[3][7],
    38         C1[3][8], Map[3][8], C2[3][8]);
    39     printf("	--##---+---+---||---+---+---||---+---+---##
    ");
    40     printf("	5-##%c%d%c|%c%d%c|%c%d%c||%c%d%c|%c%d%c|%c%d%c||%c%d%c|%c%d%c|%c%d%c##
    ",
    41         C1[4][0], Map[4][0], C2[4][0], C1[4][1], Map[4][1], C2[4][1],
    42         C1[4][2], Map[4][2], C2[4][2], C1[4][3], Map[4][3], C2[4][3],
    43         C1[4][4], Map[4][4], C2[4][4], C1[4][5], Map[4][5], C2[4][5],
    44         C1[4][6], Map[4][6], C2[4][6], C1[4][7], Map[4][7], C2[4][7],
    45         C1[4][8], Map[4][8], C2[4][8]);
    46     printf("	--##---+---+---||---+---+---||---+---+---##
    ");
    47     printf("	6-##%c%d%c|%c%d%c|%c%d%c||%c%d%c|%c%d%c|%c%d%c||%c%d%c|%c%d%c|%c%d%c##
    ",
    48         C1[5][0], Map[5][0], C2[5][0], C1[5][1], Map[5][1], C2[5][1],
    49         C1[5][2], Map[5][2], C2[5][2], C1[5][3], Map[5][3], C2[5][3],
    50         C1[5][4], Map[5][4], C2[5][4], C1[5][5], Map[5][5], C2[5][5],
    51         C1[5][6], Map[5][6], C2[5][6], C1[5][7], Map[5][7], C2[5][7],
    52         C1[5][8], Map[5][8], C2[5][8]);
    53     printf("	==##===========++===========++===========##
    ");
    54     printf("	7-##%c%d%c|%c%d%c|%c%d%c||%c%d%c|%c%d%c|%c%d%c||%c%d%c|%c%d%c|%c%d%c##
    ",
    55         C1[6][0], Map[6][0], C2[6][0], C1[6][1], Map[6][1], C2[6][1],
    56         C1[6][2], Map[6][2], C2[6][2], C1[6][3], Map[6][3], C2[6][3],
    57         C1[6][4], Map[6][4], C2[6][4], C1[6][5], Map[6][5], C2[6][5],
    58         C1[6][6], Map[6][6], C2[6][6], C1[6][7], Map[6][7], C2[6][7],
    59         C1[6][8], Map[6][8], C2[6][8]);
    60     printf("	--##---+---+---||---+---+---||---+---+---##
    ");
    61     printf("	8-##%c%d%c|%c%d%c|%c%d%c||%c%d%c|%c%d%c|%c%d%c||%c%d%c|%c%d%c|%c%d%c##
    ",
    62         C1[7][0], Map[7][0], C2[7][0], C1[7][1], Map[7][1], C2[7][1],
    63         C1[7][2], Map[7][2], C2[7][2], C1[7][3], Map[7][3], C2[7][3],
    64         C1[7][4], Map[7][4], C2[7][4], C1[7][5], Map[7][5], C2[7][5],
    65         C1[7][6], Map[7][6], C2[7][6], C1[7][7], Map[7][7], C2[7][7],
    66         C1[7][8], Map[7][8], C2[7][8]);
    67     printf("	--##---+---+---||---+---+---||---+---+---##
    ");
    68     printf("	9-##%c%d%c|%c%d%c|%c%d%c||%c%d%c|%c%d%c|%c%d%c||%c%d%c|%c%d%c|%c%d%c##
    ",
    69         C1[8][0], Map[8][0], C2[8][0], C1[8][1], Map[8][1], C2[8][1],
    70         C1[8][2], Map[8][2], C2[8][2], C1[8][3], Map[8][3], C2[8][3],
    71         C1[8][4], Map[8][4], C2[8][4], C1[8][5], Map[8][5], C2[8][5],
    72         C1[8][6], Map[8][6], C2[8][6], C1[8][7], Map[8][7], C2[8][7],
    73         C1[8][8], Map[8][8], C2[8][8]);
    74     printf("	==#########################################
    ");
    75     return ;
    76 }
    View Code

    附加几个测试数据:

     1 000010054
     2 800000000
     3 000000000
     4 650400000
     5 000002730
     6 000000000
     7 210000800
     8 700000300
     9 000350000
    10 
    11 008900070
    12 053000000
    13 000000000
    14 760100090
    15 200000000
    16 000080000
    17 000020805
    18 400007000
    19 000000300
    20 
    21 800000000
    22 003600000
    23 070090200
    24 050007000
    25 000045700
    26 000100030
    27 001000068
    28 008500010
    29 090000400
    30 
    31 000064000
    32 000000000
    33 910000070
    34 700000000
    35 000900010
    36 406008000
    37 000000408
    38 000002600
    39 500100000
    40 
    41 205600000
    42 100007003
    43 008000000
    44 040031000
    45 000000820
    46 000090000
    47 000000000
    48 030000001
    49 000200500
    50 
    51 005300000
    52 800000020
    53 070010500
    54 400005300
    55 010070006
    56 003200080
    57 060500009
    58 004000030
    59 000009700
    60 
    61 005890060
    62 001000005
    63 400010200
    64 700900006
    65 500000002
    66 060027050
    67 008005001
    68 040709500
    69 200000300
    View Code
  • 相关阅读:
    app接口开发(php)
    eclipse JRE(unbound)问题
    HTTP状态码详解
    HTTP方法
    项目开发注意事项及技巧
    JavaWeb 路径问题
    POJ 3264 Balanced Lineup(RMQ_ST)
    了解NoSQL
    多表查询(章节摘要)
    ios UITableView 获取点击cell对象
  • 原文地址:https://www.cnblogs.com/Gster/p/9248352.html
Copyright © 2020-2023  润新知