我目前找到的最快的數獨求解程式

lt發表於2016-09-27

瓶哥SuDoKu_DLX_9*9 程式基礎上新增了檔案操作。 測試檔案來自
http://staffhome.ecm.uwa.edu.au/~00013890/sudokumin.php
用vc2010的cl sudokudlx.cpp /MD -O2編譯,執行總時間2.7秒,絕大部分單個問題都不足1毫秒。瓶哥說只比他的dfs9*9 程式快4倍是不準確的。他的測試用例過少,我用dfs解第一個問題就花了10秒。

#include <cstdio>
#include <cstring>
#include <ctime>
const int XSIZE = 3; 
const int SIZE = XSIZE * XSIZE;
const int MAX_C = SIZE * SIZE * 4;                    //最大列 
const int MAX_R = SIZE * SIZE * SIZE;                 //最大行
const int MAX_SUDOKU = SIZE * SIZE;                   //數獨矩陣大小
const int MAX_LINK = MAX_C * MAX_R;                   //連結串列最大範圍

int L[MAX_LINK],R[MAX_LINK],U[MAX_LINK],D[MAX_LINK];  //抽象連結串列
int C[MAX_LINK],O[MAX_LINK],S[MAX_C],H[MAX_R];        //C&O代表列&行,S每一列的節點數,H每一行的第一個節點
int NodeNumber,RecordNumber;                          //用來指向節點
int state[MAX_SUDOKU],ans[MAX_SUDOKU],record[MAX_SUDOKU];
//////////////////////Dancing Links模版//////////////////////
void init(void);        //Dancing Links的抽象連結串列初始化 
void insert(int,int);   //在連結串列的一個位置中新增標記 
void remove(int);       //刪除一列,同時刪除這一列中的行 
void resume(int);       //恢復一列,同時恢復這一列中的行
//////////////////////Dancing Links模版//////////////////////
bool input(void)
{
   char buffer[SIZE+1][SIZE+1];//留一個空間 
   if(scanf("%s",buffer[0])==EOF)   return false;
   for(int i=1;i<SIZE;i++)
      scanf("%s",buffer[i]);
   memset(state,0,sizeof(state));
   for(int i=0;i<SIZE;i++)
      for(int j=0;j<SIZE;j++)
         {
            if(buffer[i][j]!='0')
               state[i*SIZE+j]=buffer[i][j]-'0';
         }
   return true;
}
   char buffer2[SIZE*SIZE+3];//留一個空間給換行符 
bool input2(FILE* f)
{
   if(NULL== fgets(buffer2,SIZE*SIZE+2,f))
     return false;
   memset(state,0,sizeof(state));
   for(int i=0;i<SIZE;i++)
      for(int j=0;j<SIZE;j++)
         {
            //if(buffer[i][j]!='0')
               state[i*SIZE+j]=buffer2[i*SIZE+j]-'0';
         }
   return true;
}
void add(int i,int j,int k)
{
   int row=i*MAX_SUDOKU+j*SIZE+k;
   insert(row,i*SIZE+j+1);//注意 
   insert(row,i*SIZE+k+MAX_SUDOKU);
   insert(row,j*SIZE+MAX_SUDOKU*2+k);
   insert(row,(i/XSIZE*XSIZE +j/XSIZE)*SIZE+MAX_SUDOKU*3+k);
}

void build(void)
{
   int pos,row;
   for(int i=0;i<SIZE;i++)
      for(int j=0;j<SIZE;j++)
         {
            pos=i*SIZE+j;
            if(state[pos]!=0)
               {
                add(i,j,state[pos]);
               }
            else if(state[pos]==0)
               {
                  for(int k=1;k<=SIZE;k++)
                     {
                        add(i,j,k);
                     }   
               }
         }   
}

bool dfs(int k)
{
   if(!R[0])
      {
         RecordNumber=k;
         return true;   
      }
   int count=~(1<<31),c;
   for(int i=R[0];i;i=R[i])
      {
         if(S[i]<count)
            {
               count=S[i];
               c=i;
               if(count==1)
                  break;   
            }  
      }
   remove(c);
   for(int i=D[c];i!=c;i=D[i])
      {
         for(int j=R[i];j!=i;j=R[j])
            {
               remove(C[j]);   
            }
         record[k]=O[i];
         if(dfs(k+1))
            return true;
         for(int j=L[i];j!=i;j=L[j])
            {
               resume(C[j]);   
            }  
      }
   resume(c);
   return false;
}

void output(void)
{
   for(int i=0;i<RecordNumber;i++)
      {
         ans[(record[i]-1)/SIZE]=(record[i]-1)%SIZE+1;
      }
   for(int i=0;i<SIZE;i++)
      {
         for(int j=0;j<SIZE;j++)
            printf("%-2d",ans[i*SIZE+j]);
         printf("\n");  
      }
}
void output2(FILE* f )
{
   for(int i=0;i<RecordNumber;i++)
      {
         ans[(record[i]-1)/SIZE]=(record[i]-1)%SIZE+1;
      }
   for(int i=0;i<SIZE;i++)
      {
         for(int j=0;j<SIZE;j++)
            fprintf(f,"%-2d",ans[i*SIZE+j]);
         fprintf(f,"\n");  
      }
}
int main()
{
   FILE *fp=fopen("d:\\sudoku17.txt","rt");
   FILE *fo=fopen("d:\\sudoku17res.txt","wt");
   while(input2(fp))
      {
         time_t start=clock();
         init();
         build();
         dfs(0);
         fprintf(fo,"%s\n",buffer2);
         output2(fo);
         fprintf(fo,"Time:%ldMs\n",clock()-start);
      }
      fclose(fp);
      fclose(fo);
   return 0;   
}

//////////////////////Dancing Links模版//////////////////////
void init(void)
{
   for(int i=0;i<=MAX_C;i++)
      {
         L[i]=i-1;
         R[i]=i+1;
         U[i]=i;
         D[i]=i;
         C[i]=i;
         O[i]=0;   
      }
   L[0]=MAX_C;
   R[MAX_C]=0;
   NodeNumber=MAX_C+1;
   memset(S,0,sizeof(S));
   memset(H,0,sizeof(H));
}

void insert(int i,int j)   
{
   if(H[i])
      {
         L[NodeNumber]=L[H[i]];
         R[NodeNumber]=H[i];
         L[R[NodeNumber]]=NodeNumber;
         R[L[NodeNumber]]=NodeNumber;
      }
   else
      {
         L[NodeNumber]=NodeNumber;
         R[NodeNumber]=NodeNumber;
         H[i]=NodeNumber;
      }
   U[NodeNumber]=U[j];
   D[NodeNumber]=j;
   U[D[NodeNumber]]=NodeNumber;
   D[U[NodeNumber]]=NodeNumber;
   C[NodeNumber]=j;
   O[NodeNumber]=i;
   S[j]++;
   NodeNumber++;
}

void remove(int c)
{
   L[R[c]]=L[c];
   R[L[c]]=R[c];
   for(int i=D[c];i!=c;i=D[i])
      {
         for(int j=R[i];j!=i;j=R[j])
            {
               U[D[j]]=U[j];
               D[U[j]]=D[j];
               S[C[j]]--;
            }
      } 
}

void resume(int c)
{
   for(int i=U[c];i!=c;i=U[i])
      {
         for(int j=L[i];j!=i;j=L[j])
            {
               U[D[j]]=j;
               D[U[j]]=j;
               S[C[j]]++;
            } 
      }
   L[R[c]]=c;
   R[L[c]]=c;   
}
/*
070680050
000000001
409507000
560000340
000000000
034000017
000703804
300000000
090015030
*/

相關文章