【算法】Dancing Links (DLX) II

From: http://blog.csdn.net/keyboardlabourer/article/details/13168391

1. 数独问题


前一篇中简要地介绍了DLX算法,这一篇将主要讲DLX的应用——解决数独问题。DLX本身是用来解决exact cover问题,如果有一些问题能转化成exact cover问题,也就意味着也能用DLX求解。


数独(Sudoku)问题是在一个9 * 9的格子上,分为9个宫。有一些格子是已经填好了的,你的目标是把剩下的每一个格子填上1-9中的某一个数,使得每一行、每一列、每一个宫都包含1-9每个数各一次。比如:

.2738..1.
.1...6735
.......29
3.5692.8.
.........
.6.1745.3
64.......
9518...7.
.8..6534.
就是一个数独。


有些数独比较简单,则可以用纯粹的DFS(这篇有介绍)进行暴力求解。可是有些数独用DFS求解容易TLE,这时DLX就派上用场了。但是,困难在于如何构造一个矩阵A,使得数独问题转化成exact cover问题。我们可以如此构造矩阵A:

  • 行:记录数独每一个格子所填的数。比如,1~9行依次记录数独第一个格子所填的数1~9,10~18行依次记录数独第二个格子所填的数1~9……
  • 列:1~81列记录数独的81个格子是否已填,82~162列分别记录数独的1~9有数字1~9,163~243列分别记录数独的1~9有数字1~9,244~324列分别记录数独的1~9有数字1~9。
数独的格子是从左至右从上至下地编号的。为了便于后面的计算,一律将所有的编号从0开始,包括所填的数字。比如,数独的第二个格子的编号应为1,为数独的第0行第1列;如果填数字2,则应是填1(也就是说0~8代表所填数字1~9)。如果将1格子填1,则相对应地要将A[10][1]、A[10][82]、A[10][172]、A[10][244]置为1

由上述例子可以推导得出,数独的第r行第c列填k时,相应地矩阵A中四个元素置为1:
A[9*(9*r+c)+k][9*r+c]=1
A[9*(9*r+c)+k][81+9*r+k]=1
A[9*(9*r+c)+k][162+9*c+k]=1
A[9*(9*r+c)+k][243+9*(3*(r/3)+c/3)+k]=1

从0格子开始,如果该格子在初始情况下已经填好,相应地将矩阵A中元素置为1;如果该格子为空,则依次填0~8,并相应地矩阵A中元素置为1。如此数独问题转化成了exact cover问题:求矩阵A的行集合(共有81行)使得每列有且仅有一个1。在 矩阵A构造出来之后,只需将A改由双向十字链表存储,即可用DLX求解了。


2. 问题


2.1 POJ 3074


在将A改由双向十字链表存储时,用到了前一篇的init函数,并用到了G[ ]保存节点所在的行。注意到dfs函数中O[ ]记录的是搜索结果行中的一个元素,由于搜索结果共有81行,那么O[ ]应该开到81。在建双向十字链表时,是从1开始编号的。因此,G[O[ ]]-1才表示搜索结果在矩阵A中的所在行。矩阵A的每一行表示了对应的格子所填的数,G[O[ ]]表示了(G[O[ ]]-1)/9格子填(G[O[ ]]-1)%9。

源代码:
3074Accepted1140K79MSC2673B2013-10-27 11:08:2
  1. #include "stdio.h"  
  2. #include "string.h"  
  3.   
  4. #define MAXR 729  
  5. #define MAXC 324  
  6. #define MAXN 3241   //4*MAXR+MAXC+1  
  7.   
  8. int L[MAXN],R[MAXN],U[MAXN],D[MAXN],C[MAXN],G[MAXN],S[MAXC+1],O[81],H[MAXR+1];  
  9. int A[MAXR][MAXC],ans[81];  
  10. char sudoku[81];  
  11.   
  12. void fill(int r,int c,int k)              //(r,c) of sudoku is filled with number k  
  13. {  
  14.     int grid=9*r+c, row=9*(9*r+c)+k;  
  15.     A[row][grid]=1;  
  16.     A[row][81+9*r+k]=1;  
  17.     A[row][162+9*c+k]=1;  
  18.     A[row][243+9*(3*(r/3)+c/3)+k]=1;  
  19. }  
  20.   
  21. void construct()                          //construct matrix A  
  22. {  
  23.     int i,j,r,c;  
  24.     memset(A,0,sizeof(A));  
  25.     for(i=0;i<81;i++)  
  26.     {  
  27.         r=i/9;  c=i%9;  
  28.         if(sudoku[i]=='.')  
  29.         {  
  30.             for(j=0;j<9;j++)  
  31.                 fill(r,c,j);  
  32.         }  
  33.         else fill(r,c,sudoku[i]-'1');  
  34.     }  
  35. }  
  36.   
  37. void build_cross_list()                   //build the cross list of matrix A  
  38. {  
  39.     int i,j,count;  
  40.     for(i=1;i<=MAXC;i++)              
  41.     {  
  42.         L[i]=i-1;   R[i]=i+1;  
  43.         U[i]=i;     D[i]=i;  
  44.         C[i]=i;      
  45.     }  
  46.     L[0]=MAXC;   R[0]=1;  
  47.     R[MAXC]=0;  
  48.       
  49.     memset(H,-1,sizeof(H));  
  50.     memset(S,0,sizeof(S));  
  51.     count=MAXC+1;  
  52.       
  53.     for(i=1;i<=MAXR;i++)    
  54.         for(j=1;j<=MAXC;j++)    
  55.         {    
  56.             if(!A[i-1][j-1])  continue;    
  57.               
  58.             if(H[i]==-1)                         
  59.                 H[i]=L[count]=R[count]=count;    
  60.             else        
  61.             {    
  62.                 L[count]=L[H[i]];    R[count]=H[i];    
  63.                 R[L[H[i]]]=count;    L[H[i]]=count;    
  64.             }    
  65.               
  66.             U[count]=U[j];   D[count]=j;               
  67.             D[U[j]]=count;   U[j]=count;    
  68.             C[count]=j;      G[count]=i;      //record the row of the node                           
  69.             S[j]++;                         
  70.             count++;    
  71.         }    
  72. }  
  73.   
  74. void re_move(int c)  
  75. {  
  76.     int i,j;  
  77.     L[R[c]]=L[c];                        
  78.     R[L[c]]=R[c];  
  79.     for(i=D[c];i!=c;i=D[i])             
  80.         for(j=R[i];j!=i;j=R[j])  
  81.         {  
  82.             U[D[j]]=U[j];  
  83.             D[U[j]]=D[j];  
  84.             S[C[j]]--;                  
  85.         }  
  86. }  
  87.   
  88. void resume(int c)  
  89. {  
  90.     int i,j;  
  91.     for(i=U[c];i!=c;i=U[i])  
  92.         for(j=L[i];j!=i;j=L[j])  
  93.         {  
  94.             S[C[j]]++;  
  95.             U[D[j]]=j;  
  96.             D[U[j]]=j;  
  97.         }  
  98.         L[R[c]]=c;  
  99.         R[L[c]]=c;  
  100. }  
  101.   
  102. int dfs(int depth)  
  103. {  
  104.     int i,j,c,min=10000;  
  105.     if(R[0]==0)                                    //print the answer  
  106.     {  
  107.         for(i=0;i<depth;i++)  
  108.             ans[(G[O[i]]-1)/9]=(G[O[i]]-1)%9+1;  
  109.         for(i=0;i<81;i++)  
  110.             printf("%d",ans[i]);  
  111.         printf("\n");  
  112.         return 1;     
  113.     }  
  114.       
  115.     for(i=R[0];i!=0;i=R[i])             
  116.         if(S[i]<min)  
  117.         {  
  118.             min=S[i];  
  119.             c=i;  
  120.         }     
  121.     re_move(c);  
  122.           
  123.     for(i=D[c];i!=c;i=D[i])  
  124.     {  
  125.         O[depth]=i;                     
  126.         for(j=R[i];j!=i;j=R[j])  
  127.             re_move(C[j]);  
  128.               
  129.         if(dfs(depth+1))   return 1;  
  130.               
  131.         for(j=L[i];j!=i;j=L[j])          
  132.             resume(C[j]);  
  133.     }  
  134.           
  135.     resume(c);  
  136.     return 0;  
  137. }  
  138.   
  139. int main()  
  140. {  
  141.     while(scanf("%s",sudoku)&&sudoku[0]!='e')  
  142.     {  
  143.         construct();  
  144.         build_cross_list();  
  145.         dfs(0);  
  146.     }  
  147.     return 0;  
  148. }  


2.2 POJ 3076


16*16的数独,将3074中的一些数更改一下就可以了。

PE了一次,每个测试样例后需要空一行。

源代码:
3076Accepted16892K422MSC3046B2013-10-27 16:28:41
  1. #include "stdio.h"  
  2. #include "string.h"  
  3.   
  4. #define MAXR 4096  
  5. #define MAXC 1024  
  6. #define MAXN 17409   //4*MAXR+MAXC+1  
  7.   
  8. int L[MAXN],R[MAXN],U[MAXN],D[MAXN],C[MAXN],G[MAXN],S[MAXC+1],O[256],H[MAXR+1];  
  9. int A[MAXR][MAXC];  
  10. char sudoku[16][16],ans[256];  
  11.   
  12. void fill(int r,int c,int k)              //(r,c) of sudoku is filled with number k  
  13. {  
  14.     int grid=16*r+c, row=16*(16*r+c)+k;  
  15.     A[row][grid]=1;  
  16.     A[row][256+16*r+k]=1;  
  17.     A[row][512+16*c+k]=1;  
  18.     A[row][768+16*(4*(r/4)+c/4)+k]=1;  
  19. }  
  20.   
  21. void construct()                          //construct matrix A  
  22. {  
  23.     int i,j,k;  
  24.     memset(A,0,sizeof(A));  
  25.     for(i=1;i<16;i++)  
  26.         scanf("%s",sudoku[i]);  
  27.     for(i=0;i<16;i++)  
  28.         for(j=0;j<16;j++)  
  29.         {  
  30.             if(sudoku[i][j]=='-')  
  31.             {  
  32.                 for(k=0;k<16;k++)  
  33.                     fill(i,j,k);  
  34.             }  
  35.             else fill(i,j,sudoku[i][j]-'A');  
  36.         }  
  37. }  
  38.   
  39.   
  40. void build_cross_list()                   //build the cross list of matrix A  
  41. {  
  42.     int i,j,count;  
  43.     for(i=1;i<=MAXC;i++)              
  44.     {  
  45.         L[i]=i-1;   R[i]=i+1;  
  46.         U[i]=i;     D[i]=i;  
  47.         C[i]=i;      
  48.     }  
  49.     L[0]=MAXC;   R[0]=1;  
  50.     R[MAXC]=0;  
  51.       
  52.     memset(H,-1,sizeof(H));  
  53.     memset(S,0,sizeof(S));  
  54.     count=MAXC+1;  
  55.       
  56.     for(i=1;i<=MAXR;i++)    
  57.         for(j=1;j<=MAXC;j++)    
  58.         {    
  59.             if(!A[i-1][j-1])  continue;    
  60.               
  61.             if(H[i]==-1)                         
  62.                 H[i]=L[count]=R[count]=count;    
  63.             else        
  64.             {    
  65.                 L[count]=L[H[i]];    R[count]=H[i];    
  66.                 R[L[H[i]]]=count;    L[H[i]]=count;    
  67.             }    
  68.               
  69.             U[count]=U[j];   D[count]=j;               
  70.             D[U[j]]=count;   U[j]=count;    
  71.             C[count]=j;      G[count]=i;      //record the row of the node                           
  72.             S[j]++;                         
  73.             count++;    
  74.         }    
  75. }  
  76.   
  77. void re_move(int c)  
  78. {  
  79.     int i,j;  
  80.     L[R[c]]=L[c];                        
  81.     R[L[c]]=R[c];  
  82.     for(i=D[c];i!=c;i=D[i])             
  83.         for(j=R[i];j!=i;j=R[j])  
  84.         {  
  85.             U[D[j]]=U[j];  
  86.             D[U[j]]=D[j];  
  87.             S[C[j]]--;                  
  88.         }  
  89. }  
  90.   
  91. void resume(int c)  
  92. {  
  93.     int i,j;  
  94.     for(i=U[c];i!=c;i=U[i])  
  95.         for(j=L[i];j!=i;j=L[j])  
  96.         {  
  97.             S[C[j]]++;  
  98.             U[D[j]]=j;  
  99.             D[U[j]]=j;  
  100.         }  
  101.         L[R[c]]=c;  
  102.         R[L[c]]=c;  
  103. }  
  104.   
  105. int dfs(int depth)  
  106. {  
  107.     int i,j,c,min=10000;  
  108.     if(R[0]==0)                                    //print the answer  
  109.     {  
  110.         for(i=0;i<depth;i++)  
  111.             ans[(G[O[i]]-1)/16]=(G[O[i]]-1)%16+'A';  
  112.         for(i=0;i<16;i++)  
  113.         {  
  114.             for(j=0;j<16;j++)  
  115.                 printf("%c",ans[16*i+j]);  
  116.             printf("\n");  
  117.         }  
  118.         printf("\n");  
  119.         return 1;     
  120.     }  
  121.       
  122.     for(i=R[0];i!=0;i=R[i])             
  123.         if(S[i]<min)  
  124.         {  
  125.             min=S[i];  
  126.             c=i;  
  127.         }     
  128.     re_move(c);  
  129.           
  130.     for(i=D[c];i!=c;i=D[i])  
  131.     {  
  132.         O[depth]=i;                     
  133.         for(j=R[i];j!=i;j=R[j])  
  134.             re_move(C[j]);  
  135.               
  136.         if(dfs(depth+1))   return 1;  
  137.               
  138.         for(j=L[i];j!=i;j=L[j])          
  139.             resume(C[j]);  
  140.     }  
  141.           
  142.     resume(c);  
  143.     return 0;  
  144. }  
  145.   
  146. int main()  
  147. {  
  148.     while(scanf("%s",sudoku[0])!=EOF)  
  149.     {  
  150.         construct();  
  151.         build_cross_list();  
  152.         dfs(0);  
  153.     }  
  154.     return 0;  


  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值