zoukankan      html  css  js  c++  java
  • Dancing_Links总结 【by AbandonZHANG】

    参考文章:

    1. 《Dancing Links》 by Donald E.Knuth (Knuth老人家以这篇论文公布和诠释了他发明的Dancing_Links)

    附一个中文版的地址:http://sqybi.com/works/dlxcn/(仅供英语不好的人看。。。有能力的还是看原文比较好~~~)

    2. 《Dancing Links在搜索中的应用》 by momodi (里面有 momodi 大牛的DLX模板)

    Dancing Links

    Dancing Links实质上就是一个能够“优美地”进行恢复删除操作的双向链表。Knuth更多的把它定义为一种技巧而不是新的数据结构。

    这种技巧便是用  (1)L[R[x]]=L[x],  R[L[x]]=R[x]  进行删除结点操作

    和用       (2)L[R[x]]=x,  R[L[x]]=x     进行恢复结点操作。

    整个技巧的亮点在于(2)可以如此“优美地”恢复已经删除的结点。当用这种技巧不断进行删除、恢复操作时,链表的指针就像在跳舞一样,所以Knuth愿意叫它Dancing Links。

    那么随之而来就是另一个重要的问题:这个优美的东西能够干什么。

    Dancing Links最重要的一个特征就是它可以高效的不断删除、恢复结点,尤其是恢复。那么哪里会用到恢复结点呢?最显然的当然是回溯,即深度优先搜索(DFS)。所以Dancing Links一个重要的应用当然就是优化DFS。

    精确覆盖问题------DLX (from  Wiki )

     

    具体到一个模型就是

    给定一个由0 和1 组成的矩阵,是否能找到一个行的集合,使得

    集合中每一列都恰好包含一个1?例如,下面这个矩阵

    list 3(3)

    就包含了这样一个集合(第1,4,5行)。我们把列想象成全集的一些元素,而行看作全集的一些子集;或者我们可以把行想象成全集的一些元素,而把列看作全集的一些子集;那么这个问题就是要求寻找一批元素,它们与每个子集恰好有一个交点。不管怎么说,这都是一个很难的问题,众所周知,当每行恰包含3个1时,这是个一个NP-完全问题。自然,作为首选的算法就是回溯了。

     

     

    解决精确覆盖问题(Algorithm X ---> DLX)

    (from 《Dancing Links》D.Knuth ---CN (论文已经讲的很清楚了~~~)

      对于接下来的非确定性算法,Knuth将称之为X算法,它能够找到由特定的01矩阵A定义的精确覆盖问题的所有解。

    如果A是空的,问题解决;成功终止。
    否则,选择一个列c(确定的)。
    选择一个行r,满足 A[r, c]=1 (不确定的)。
    把r包含进部分解。
    对于所有满足 A[r,j]=1 的j,
      从矩阵A中删除第j列;
      对于所有满足 A[i,j]=1 的i,
        从矩阵A中删除第i行。
    在不断减少的矩阵A上递归地重复上述算法。

    DLX C++模板:

    DLX 模板
      1 DLX 模板
      2 
      3 //Dancing Links
      4 const int N = 350;
      5 const int M = 20 ;
      6 int R[M*N],L[M*N],U[M*N],D[M*N],O[M*N],S[M*N],C[M*N];
      7 int h;      //head
      8 int n,m;
      9 
     10 void remove(int &c)
     11 {
     12     L[R[c]]=L[c];
     13     R[L[c]]=R[c];
     14     for (int i=D[c];i!=c;i=D[i])
     15     //remove i that A[i,c]==1
     16         for (int j=R[i];j!=i;j=R[j])
     17         {
     18             //remove j that A[i,j]==1
     19             U[D[j]]=U[j];
     20             D[U[j]]=D[j];
     21             --S[C[j]];
     22             //decrese the count of column C[j];
     23         }
     24 }
     25 
     26 void resume(int &c)
     27 {
     28     for (int i=U[c];i!=c;i=U[i])
     29         for (int j=L[i];j!=i;j=L[j])
     30         {
     31             U[D[j]]=j;
     32             D[U[j]]=j;
     33             ++S[C[j]];
     34         }
     35 
     36     L[R[c]]=c;
     37     R[L[c]]=c;
     38 }
     39 bool dfs(int k)
     40 {
     41     if (R[h] == h)
     42     {
     43         //one of the answers has been found.
     44         return true;
     45     }
     46 
     47     int c,s=INT_MAX;
     48     for (int i=R[h];i!=h;i=R[i])
     49         if (S[i]<s)
     50         {
     51             s=S[i];
     52             c=i;
     53         }
     54 
     55     remove(c);
     56     for (int i=D[c];i!=c;i=D[i])
     57     {
     58         O[k]=i;
     59         for (int j=R[i];j!=i;j=R[j])
     60             remove(C[j]);
     61         if (dfs(k+1))
     62             return true;
     63         for (int j=L[i];j!=i;j=L[j])
     64             resume(C[j]);
     65     }
     66     resume(c);
     67     return false;
     68 
     69 }
     70 
     71 
     72 //根据题目自己写初始化构造链表函数
     73 void Initialize_DancingLinks()
     74 {
     75     h=0;
     76 
     77     //initialize the column head list.
     78     L[0]=m;
     79     for (int j=1;j<=m;j++)
     80     {
     81         R[j-1]=j;
     82         L[j]=j-1;
     83         S[j]=0;
     84     }
     85     R[m]=0;
     86 
     87     //initialize Dancing-Links
     88     for (int j=1;j<=m;j++)
     89     {
     90         for (int i=1;i<=n;i++)
     91         {
     92             U[i*m+j]=(i-1)*m+j;
     93             D[(i-1)*m+j]=i*m+j;
     94             C[i*m+j]=j;
     95             S[j]++;
     96         }
     97         D[n*m+j]=j;
     98         U[j]=n*m+j;
     99     }
    100 
    101     for (int i=1;i<=n;i++)
    102     {
    103         for (int j=2;j<=m;j++)
    104         {
    105             R[i*m+j-1]=i*m+j;
    106             L[i*m+j]=i*m+j-1;
    107         }
    108         R[i*m+m]=i*m+1;
    109         L[i*m+1]=i*m+m;
    110     }
    111 
    112     int d[20][305];
    113     for (int i=1;i<=n;i++)
    114         for (int j=1;j<=m;j++)
    115             scanf("%d",&d[i][j]);
    116 
    117     for (int i=1;i<=n;i++)
    118         for (int j=1;j<=m;j++)
    119             if (d[i][j]==0)
    120             {
    121                 D[U[i*m+j]]=D[i*m+j];
    122                 U[D[i*m+j]]=U[i*m+j];
    123                 S[C[i*m+j]]--;
    124                 R[L[i*m+j]]=R[i*m+j];
    125                 L[R[i*m+j]]=L[i*m+j];
    126             }
    127 }
    128 
    129 //在main()里调用dfs(0)执行程序

    这里说一下根据矩阵怎么建立链表:(不推荐此法了……)(对照模板里面Initialize_DancingLinks()函数看)

    1.首先不管矩阵是0还是1都加入到链表中。因为这样好给新建立的链表编号--->假如有n行m列矩阵,1-m号表示1-m列表头。那么第i行j列的结点号即为i*m+j。

    2.遍历链表(表已经建立了哪行哪列下标号也很清楚不难吧~~~),如果当前位置为0,则删除该结点。(L[R[x]]=L[x],  R[L[x]]=R[x],  U[D[x]]=U[x],  D[U[x]]=D[x])

    (这种方法很偷懒吧?~^_^……)

     

    PS:这种建表方式也浪费了大量的时间。矩阵小点儿还好,解决数独就不行了。(POJ 3074用这种建法TLE到死。。。标准建法200MS。。。)

    所以建立链表的方法还是以下面POJ 3074的代码中的方法(即数独模板中的方法)为准。

     

    习题:

     

    POJ 3740  (DLX入门题,就是上面那道01矩阵精确覆盖的题)

    http://poj.org/problem?id=3740

    POJ 3740
      1 POJ 3740
      2 
      3 #include <iostream>
      4 #include <cstdio>
      5 #include <cstdlib>
      6 #include <cmath>
      7 #include <iomanip>
      8 #include <climits>
      9 #include <vector>
     10 #include <stack>
     11 #include <queue>
     12 #include <set>
     13 #include <map>
     14 #include <algorithm>
     15 #include <string>
     16 #include <cstring>
     17 
     18 using namespace std;
     19 
     20 typedef long long LL;
     21 const double EPS = 1e-11;
     22 
     23 //Dancing Links
     24 const int N = 350;
     25 const int M = 20 ;
     26 int R[M*N],L[M*N],U[M*N],D[M*N],O[M*N],S[M*N],C[M*N];
     27 int h;      //head
     28 int n,m;
     29 
     30 void remove(int &c)
     31 {
     32     L[R[c]]=L[c];
     33     R[L[c]]=R[c];
     34     for (int i=D[c];i!=c;i=D[i])
     35     //remove i that A[i,c]==1
     36         for (int j=R[i];j!=i;j=R[j])
     37         {
     38             //remove j that A[i,j]==1
     39             U[D[j]]=U[j];
     40             D[U[j]]=D[j];
     41             --S[C[j]];
     42             //decrese the count of column C[j];
     43         }
     44 }
     45 
     46 void resume(int &c)
     47 {
     48     for (int i=U[c];i!=c;i=U[i])
     49         for (int j=L[i];j!=i;j=L[j])
     50         {
     51             U[D[j]]=j;
     52             D[U[j]]=j;
     53             ++S[C[j]];
     54         }
     55 
     56     L[R[c]]=c;
     57     R[L[c]]=c;
     58 }
     59 bool dfs(int k)
     60 {
     61     if (R[h] == h)
     62     {
     63         //one of the answers has been found.
     64         return true;
     65     }
     66 
     67     int c,s=INT_MAX;
     68     for (int i=R[h];i!=h;i=R[i])
     69         if (S[i]<s)
     70         {
     71             s=S[i];
     72             c=i;
     73         }
     74 
     75     remove(c);
     76     for (int i=D[c];i!=c;i=D[i])
     77     {
     78         O[k]=i;
     79         for (int j=R[i];j!=i;j=R[j])
     80             remove(C[j]);
     81         if (dfs(k+1))
     82             return true;
     83         for (int j=L[i];j!=i;j=L[j])
     84             resume(C[j]);
     85     }
     86     resume(c);
     87     return false;
     88 
     89 }
     90 
     91 void Initialize_DancingLinks()
     92 {
     93     h=0;
     94 
     95     //initialize the column head list.
     96     L[0]=m;
     97     for (int j=1;j<=m;j++)
     98     {
     99         R[j-1]=j;
    100         L[j]=j-1;
    101         S[j]=0;
    102     }
    103     R[m]=0;
    104 
    105     //initialize Dancing-Links
    106     for (int j=1;j<=m;j++)
    107     {
    108         for (int i=1;i<=n;i++)
    109         {
    110             U[i*m+j]=(i-1)*m+j;
    111             D[(i-1)*m+j]=i*m+j;
    112             C[i*m+j]=j;
    113             S[j]++;
    114         }
    115         D[n*m+j]=j;
    116         U[j]=n*m+j;
    117     }
    118 
    119     for (int i=1;i<=n;i++)
    120     {
    121         for (int j=2;j<=m;j++)
    122         {
    123             R[i*m+j-1]=i*m+j;
    124             L[i*m+j]=i*m+j-1;
    125         }
    126         R[i*m+m]=i*m+1;
    127         L[i*m+1]=i*m+m;
    128     }
    129 
    130     int d[20][305];
    131     for (int i=1;i<=n;i++)
    132         for (int j=1;j<=m;j++)
    133             scanf("%d",&d[i][j]);
    134 
    135     for (int i=1;i<=n;i++)
    136         for (int j=1;j<=m;j++)
    137             if (d[i][j]==0)
    138             {
    139                 D[U[i*m+j]]=D[i*m+j];
    140                 U[D[i*m+j]]=U[i*m+j];
    141                 S[C[i*m+j]]--;
    142                 R[L[i*m+j]]=R[i*m+j];
    143                 L[R[i*m+j]]=L[i*m+j];
    144             }
    145 }
    146 
    147 int main()
    148 {
    149     while(scanf("%d%d",&n,&m)!=EOF)
    150     {
    151         memset(C,0,sizeof(C));
    152         Initialize_DancingLinks();
    153         if (dfs(0))
    154             printf("Yes, I found it\n");
    155         else
    156             printf("It is impossible\n");
    157     }
    158     return 0;
    159 }
    数独(Sudoku)转化精确覆盖问题思路:

      转化精确覆盖问题的思路一般是:  有多少种选择就建立多少行;有多少个限制就建立多少列 

      比如数独问题转化思路就是:(N阶数独)设置N*N*N行。每一行的状态表示数独第i行第j列数为k。设置(N+N+N)*N+N*N(即4*N*N)列。前面(N+N+N)*N列状态分别表示第i行有数k、第j列有数k、第p个九宫格有数k。后面N*N列限制数独的每个格子只能填一个数。如果没有后面N*N列限制,则搜索时一个格子可能被填2个数。

      然后就是注意最后答案的转化(具体看模板)

     

    POJ 3074   (数独入门题,标准9*9数独 ------Sudoku模板~~~)

    http://poj.org/problem?id=3074

    POJ 3074
      1 POJ 3074
      2  #include <iostream>
      3  #include <cstdio>
      4  #include <cstdlib>
      5  #include <cmath>
      6  #include <iomanip>
      7  #include <climits>
      8  #include <vector>
      9  #include <stack>
     10  #include <queue>
     11  #include <set>
     12  #include <map>
     13  #include <algorithm>
     14  #include <string>
     15  #include <cstring>
     16  
     17  using namespace std;
     18  
     19  typedef long long LL;
     20  const double EPS = 1e-11;
     21  
     22  //Dancing Links
     23  //列(N+N+N)*N+N*N=4*N*N.
     24  #define N 750   //>9*9*9
     25  #define M 350   //>4*9*9
     26  const int P=9;  //p阶数独
     27  int h;
     28  int L[N*M],R[N*M],U[N*M],D[N*M],S[N*M],C[N*M],O[N*M];
     29  
     30  int n,m;
     31  void remove (const int &c)
     32  {
     33      L[R[c]]=L[c];
     34      R[L[c]]=R[c];
     35      for (int i=D[c];i!=c;i=D[i])
     36          for (int j=R[i];j!=i;j=R[j])
     37          {
     38              U[D[j]]=U[j];
     39              D[U[j]]=D[j];
     40              --S[C[j]];
     41          }
     42  }
     43  
     44  void resume (const int &c)
     45  {
     46      for (int i=U[c];i!=c;i=U[i])
     47          for (int j=L[i];j!=i;j=L[j])
     48          {
     49              U[D[j]]=j;
     50              D[U[j]]=j;
     51              ++S[C[j]];
     52          }
     53      L[R[c]]=c;
     54      R[L[c]]=c;
     55  }
     56  
     57  bool Dance(int k)
     58  {
     59      if (R[h]==h)
     60      {
     61          sort(O,O+k);
     62          for (int i=0;i<k;i++)
     63              printf("%d",(O[i]-1)/m%P==0?P:((O[i]-1)/m%P));
     64          printf("\n");
     65  
     66          return true;
     67      }
     68  
     69      int c,ss=INT_MAX;
     70  
     71      for (int i=R[h];i!=h;i=R[i])
     72          if (S[i]<ss)
     73          {
     74              ss=S[i];
     75              c=i;
     76          }
     77  
     78      remove(c);
     79      for (int i=D[c];i!=c;i=D[i])
     80      {
     81          O[k]=i;
     82          for (int j=R[i];j!=i;j=R[j])
     83              remove(C[j]);
     84          if (Dance(k+1))
     85              return true;
     86          for (int j=L[i];j!=i;j=L[j])
     87              resume(C[j]);
     88      }
     89      resume(c);
     90  
     91      return false;
     92  }
     93  
     94  //Initialize
     95  void Link(char s[])
     96  {
     97      int d[N][M];
     98      memset(d,0,sizeof(d));
     99      memset(O,0,sizeof(O));
    100  
    101      //preprocess the sudoku 数独转换精确覆盖问题矩阵形式
    102      int q=0;
    103      for (int i=1;i<=P;i++)
    104          for (int j=1;j<=P;j++)
    105          {
    106              if (s[q]=='.')
    107              {
    108                  for (int k=1;k<=P;k++)
    109                  {
    110                      int rr=((i-1)*P+j-1)*P+k;                   //行。(9*9*9)行 表示数独第i行第j列数填k
    111                      d[rr][(i-1)*P+k]=1;                         //列。前(9*9)列 表示数独第i行有数k
    112                      d[rr][(j-1)*P+k+P*P]=1;                     //列。(9*9)列 表示数独第j行有数k
    113                      d[rr][((i-1)/3*3+(j-1)/3)*P+k+2*P*P]=1;     //列。(9*9)列 表示数独第p个九宫格有数k
    114                      d[rr][(i-1)*P+j+3*P*P]=1;                   //列。(9*9)列 表示数独第i行第j行有一个数(防止一个格子填多个数)
    115                  }
    116              }
    117              else
    118              {
    119                  int num=s[q]-'0';
    120                  int rr=((i-1)*P+j-1)*P+num;                 //行。(9*9*9)行 表示数独第i行第j列数填k
    121                  d[rr][(i-1)*P+num]=1;                       //列。前(9*9)列 表示数独第i行有数k
    122                  d[rr][(j-1)*P+num+P*P]=1;                   //列。(9*9)列 表示数独第j行有数k
    123                  d[rr][((i-1)/3*3+(j-1)/3)*P+num+2*P*P]=1;   //列。(9*9)列 表示数独第p个九宫格有数k
    124                  d[rr][(i-1)*P+j+3*P*P]=1;                   //列。(9*9)列 表示数独第i行第j行有一个数(防止一个格子填多个数)
    125              }
    126  
    127              q++;
    128          }
    129  
    130      //Initialize the all matrix to list.
    131      int x[N],row[N],col[M];           //x表示当前行中的第一个链,row表示当前行中上一个插入的链、col表示当前列中上一个插入的链。
    132      h=0;
    133      for (int i=1;i<=m;i++)
    134      {
    135          R[i-1]=i;
    136          L[i]=i-1;
    137          S[i]=0;
    138          col[i]=i;
    139      }
    140      col[0]=0;
    141      L[h]=m;
    142      R[m]=h;
    143  
    144      for (int i=1;i<=n;i++)
    145      {
    146          x[i]=0;                             //行第一个链表
    147          for (int j=1;j<=m;j++)
    148              if (d[i][j])
    149              {
    150                  int index=i*(4*P*P)+j;      //带插入的列表下标。
    151                  if (!x[i])
    152                  {
    153                      row[i]=x[i]=index;
    154                  }
    155                  else
    156                  {
    157                      R[row[i]]=index;
    158                      L[index]=row[i];
    159                  }
    160                  D[col[j]]=index;
    161                  U[index]=col[j];
    162                  row[i]=col[j]=index;
    163                  C[index]=j;
    164                  S[j]++;
    165              }
    166      }
    167  
    168      for (int i=1;i<=n;i++)
    169          if (x[i])
    170          {
    171              L[x[i]]=row[i];
    172              R[row[i]]=x[i];
    173          }
    174      for (int j=1;j<=m;j++)
    175      {
    176          D[col[j]]=j;
    177          U[j]=col[j];
    178      }
    179  }
    180  
    181  int main()
    182  {
    183      //freopen("test.in","r+",stdin);
    184      //freopen("test.out","w+",stdout);
    185  
    186      char s[100];
    187      n=P*P*P;
    188      m=4*P*P;
    189      while(~scanf("%s",s))
    190      {
    191          if (!strcmp(s,"end"))
    192              return 0;
    193          Link(s);
    194          Dance(0);
    195      }
    196      return 0;
    197  }

    POJ 2676  (9*9数独,和3074一样的……拿模板直接交了=。=……)

    http://poj.org/problem?id=2676

    POJ 2676
      1 #include <iostream>
      2 #include <cstdio>
      3 #include <cstdlib>
      4 #include <cmath>
      5 #include <iomanip>
      6 #include <climits>
      7 #include <vector>
      8 #include <stack>
      9 #include <queue>
     10 #include <set>
     11 #include <map>
     12 #include <algorithm>
     13 #include <string>
     14 #include <cstring>
     15 
     16 using namespace std;
     17 
     18 typedef long long LL;
     19 const double EPS = 1e-11;
     20 
     21 char s[10][10];
     22 
     23 //Dancing Links
     24 //列(N+N+N)*N+N*N=4*N*N.
     25 #define N 750
     26 #define M 350
     27 const int P=9;  //p阶数独
     28 int h;
     29 int L[N*M],R[N*M],U[N*M],D[N*M],S[M],C[N*M],O[N];
     30 bool d[N][M];
     31 
     32 int n,m;
     33 inline void remove (const int &c)
     34 {
     35     L[R[c]]=L[c];
     36     R[L[c]]=R[c];
     37     for (int i=D[c];i!=c;i=D[i])
     38         for (int j=R[i];j!=i;j=R[j])
     39         {
     40             U[D[j]]=U[j];
     41             D[U[j]]=D[j];
     42             --S[C[j]];
     43         }
     44 }
     45 
     46 inline void resume (const int &c)
     47 {
     48     for (int i=U[c];i!=c;i=U[i])
     49         for (int j=L[i];j!=i;j=L[j])
     50         {
     51             U[D[j]]=j;
     52             D[U[j]]=j;
     53             ++S[C[j]];
     54         }
     55     L[R[c]]=c;
     56     R[L[c]]=c;
     57 }
     58 
     59 bool Dance(int k)
     60 {
     61     if (R[h]==h)
     62     {
     63         sort(O,O+k);
     64         for (int i=0;i<k;i++)
     65         {
     66             printf("%d",(O[i]-1)/m%P==0?P:((O[i]-1)/m%P));
     67             if ((i+1)%P==0)
     68                 printf("\n");
     69         }
     70 
     71         return true;
     72     }
     73 
     74     int c,ss=INT_MAX;
     75 
     76     for (int i=R[h];i!=h;i=R[i])
     77         if (S[i]<ss)
     78         {
     79             ss=S[i];
     80             c=i;
     81         }
     82 
     83     remove(c);
     84     for (int i=D[c];i!=c;i=D[i])
     85     {
     86         O[k]=i;
     87         for (int j=R[i];j!=i;j=R[j])
     88             remove(C[j]);
     89         if (Dance(k+1))
     90             return true;
     91         for (int j=L[i];j!=i;j=L[j])
     92             resume(C[j]);
     93     }
     94     resume(c);
     95 
     96     return false;
     97 }
     98 
     99 //Initialize
    100 void Link()
    101 {
    102 
    103     memset(d,0,sizeof(d));
    104     memset(O,0,sizeof(O));
    105 
    106     //preprocess the sudoku 数独转换精确覆盖问题矩阵形式
    107     for (int i=1;i<=P;i++)
    108         for (int j=1;j<=P;j++)
    109         {
    110             if (s[i-1][j-1]=='0')
    111             {
    112                 for (int k=1;k<=P;k++)
    113                 {
    114                     int rr=((i-1)*P+j-1)*P+k;                   //表示数独第i行第j列数填k
    115                     d[rr][(i-1)*P+k]=1;                         //表示数独第i行有数k
    116                     d[rr][(j-1)*P+k+P*P]=1;                     //表示数独第j行有数k
    117                     d[rr][((i-1)/3*3+(j-1)/3)*P+k+2*P*P]=1;     //表示数独第p个十六宫格有数k
    118                     d[rr][(i-1)*P+j+3*P*P]=1;                   //表示数独第i行第j行有一个数(防止一个格子填多个数)
    119                 }
    120             }
    121             else
    122             {
    123                 int num=s[i-1][j-1]-'0';
    124                 int rr=((i-1)*P+j-1)*P+num;                 //表示数独第i行第j列数填k
    125                 d[rr][(i-1)*P+num]=1;                       //表示数独第i行有数k
    126                 d[rr][(j-1)*P+num+P*P]=1;                   //表示数独第j行有数k
    127                 d[rr][((i-1)/3*3+(j-1)/3)*P+num+2*P*P]=1;   //表示数独第p个十六宫格有数k
    128                 d[rr][(i-1)*P+j+3*P*P]=1;                   //表示数独第i行第j行有一个数(防止一个格子填多个数)
    129             }
    130 
    131         }
    132 
    133     //Initialize the all matrix to list.
    134     int x[N],row[N],col[M];           //x表示当前行中的第一个链,row表示当前行中上一个插入的链、col表示当前列中上一个插入的链。
    135     h=0;
    136     for (int i=1;i<=m;i++)
    137     {
    138         R[i-1]=i;
    139         L[i]=i-1;
    140         S[i]=0;
    141         col[i]=i;
    142     }
    143     col[0]=0;
    144     L[h]=m;
    145     R[m]=h;
    146 
    147     for (int i=1;i<=n;i++)
    148     {
    149         x[i]=0;                             //行第一个链表
    150         for (int j=1;j<=m;j++)
    151             if (d[i][j])
    152             {
    153                 int index=i*(4*P*P)+j;      //带插入的列表下标。
    154                 if (!x[i])
    155                 {
    156                     row[i]=x[i]=index;
    157                 }
    158                 else
    159                 {
    160                     R[row[i]]=index;
    161                     L[index]=row[i];
    162                 }
    163                 D[col[j]]=index;
    164                 U[index]=col[j];
    165                 row[i]=col[j]=index;
    166                 C[index]=j;
    167                 S[j]++;
    168             }
    169     }
    170 
    171     for (int i=1;i<=n;i++)
    172         if (x[i])
    173         {
    174             L[x[i]]=row[i];
    175             R[row[i]]=x[i];
    176         }
    177     for (int j=1;j<=m;j++)
    178     {
    179         D[col[j]]=j;
    180         U[j]=col[j];
    181     }
    182 }
    183 
    184 int main()
    185 {
    186     //freopen("test.in","r+",stdin);
    187     //freopen("test.out","w+",stdout);
    188 
    189     int t;
    190     scanf("%d",&t);
    191     n=P*P*P;
    192     m=4*P*P;
    193     memset(s,0,sizeof(s));
    194     while(t--)
    195     {
    196         for (int i=0;i<P;i++)
    197             for (int j=0;j<P;j++)
    198                 scanf("%1s",&s[i][j]);
    199         Link();
    200         Dance(0);
    201     }
    202     return 0;
    203 }

    POJ 3076  (16*16数独,较难)

    http://poj.org/problem?id=3076

    跟9*9数独比不仅仅是变个阶数那么简单。。。好多人(包括我)套模板直接MLE。。。不能用矩阵存了~得换个方式,具体的还没研究。。。

    但是在网上还是找到套模板过了的(靠!)……实在找不到我的程序和他的程序比到底哪儿又耗内存了。。。求大牛指点迷津Orz……

    POJ3076---我的MLE代码
      1 #include <iostream>
      2 #include <cstdio>
      3 #include <cstdlib>
      4 #include <cmath>
      5 #include <iomanip>
      6 #include <climits>
      7 #include <vector>
      8 #include <stack>
      9 #include <queue>
     10 #include <set>
     11 #include <map>
     12 #include <algorithm>
     13 #include <string>
     14 #include <cstring>
     15 
     16 using namespace std;
     17 
     18 typedef long long LL;
     19 const double EPS = 1e-11;
     20 
     21 char s[20][20];
     22 
     23 //Dancing Links
     24 //列(N+N+N)*N+N*N=4*N*N.
     25 #define N 4100   //>16*16*16
     26 #define M 1050   //>4*16*16
     27 const int P=16;  //p阶数独
     28 int h;
     29 int L[N*M],R[N*M],U[N*M],D[N*M],S[M],C[N*M],O[N];
     30 bool d[N][M];
     31 
     32 int n,m;
     33 inline void remove (const int &c)
     34 {
     35     L[R[c]]=L[c];
     36     R[L[c]]=R[c];
     37     for (int i=D[c];i!=c;i=D[i])
     38         for (int j=R[i];j!=i;j=R[j])
     39         {
     40             U[D[j]]=U[j];
     41             D[U[j]]=D[j];
     42             --S[C[j]];
     43         }
     44 }
     45 
     46 inline void resume (const int &c)
     47 {
     48     for (int i=U[c];i!=c;i=U[i])
     49         for (int j=L[i];j!=i;j=L[j])
     50         {
     51             U[D[j]]=j;
     52             D[U[j]]=j;
     53             ++S[C[j]];
     54         }
     55     L[R[c]]=c;
     56     R[L[c]]=c;
     57 }
     58 
     59 bool Dance(int k)
     60 {
     61     if (R[h]==h)
     62     {
     63         sort(O,O+k);
     64         for (int i=0;i<k;i++)
     65         {
     66             printf("%c",(O[i]-1)/m%P==0?'P':((O[i]-1)/m%P)+'A'-1);
     67             if ((i+1)%16==0)
     68                 printf("\n");
     69         }
     70 
     71 
     72         return true;
     73     }
     74 
     75     int c,ss=INT_MAX;
     76 
     77     for (int i=R[h];i!=h;i=R[i])
     78         if (S[i]<ss)
     79         {
     80             ss=S[i];
     81             c=i;
     82         }
     83 
     84     remove(c);
     85     for (int i=D[c];i!=c;i=D[i])
     86     {
     87         O[k]=i;
     88         for (int j=R[i];j!=i;j=R[j])
     89             remove(C[j]);
     90         if (Dance(k+1))
     91             return true;
     92         for (int j=L[i];j!=i;j=L[j])
     93             resume(C[j]);
     94     }
     95     resume(c);
     96 
     97     return false;
     98 }
     99 
    100 //Initialize
    101 void Link()
    102 {
    103 
    104     memset(d,0,sizeof(d));
    105     memset(O,0,sizeof(O));
    106 
    107     //preprocess the sudoku 数独转换精确覆盖问题矩阵形式
    108     for (int i=1;i<=P;i++)
    109         for (int j=1;j<=P;j++)
    110         {
    111             if (s[i-1][j-1]=='-')
    112             {
    113                 for (int k=1;k<=P;k++)
    114                 {
    115                     int rr=((i-1)*P+j-1)*P+k;                   //表示数独第i行第j列数填k
    116                     d[rr][(i-1)*P+k]=1;                         //表示数独第i行有数k
    117                     d[rr][(j-1)*P+k+P*P]=1;                     //表示数独第j行有数k
    118                     d[rr][((i-1)/4*4+(j-1)/4)*P+k+2*P*P]=1;     //表示数独第p个十六宫格有数k
    119                     d[rr][(i-1)*P+j+3*P*P]=1;                   //表示数独第i行第j行有一个数(防止一个格子填多个数)
    120                 }
    121             }
    122             else
    123             {
    124                 int num=s[i-1][j-1]-'A'+1;
    125                 int rr=((i-1)*P+j-1)*P+num;                 //表示数独第i行第j列数填k
    126                 d[rr][(i-1)*P+num]=1;                       //表示数独第i行有数k
    127                 d[rr][(j-1)*P+num+P*P]=1;                   //表示数独第j行有数k
    128                 d[rr][((i-1)/4*4+(j-1)/4)*P+num+2*P*P]=1;   //表示数独第p个十六宫格有数k
    129                 d[rr][(i-1)*P+j+3*P*P]=1;                   //表示数独第i行第j行有一个数(防止一个格子填多个数)
    130             }
    131 
    132         }
    133 
    134     //Initialize the all matrix to list.
    135     int x[N],row[N],col[M];           //x表示当前行中的第一个链,row表示当前行中上一个插入的链、col表示当前列中上一个插入的链。
    136     h=0;
    137     for (int i=1;i<=m;i++)
    138     {
    139         R[i-1]=i;
    140         L[i]=i-1;
    141         S[i]=0;
    142         col[i]=i;
    143     }
    144     col[0]=0;
    145     L[h]=m;
    146     R[m]=h;
    147 
    148     for (int i=1;i<=n;i++)
    149     {
    150         x[i]=0;                             //行第一个链表
    151         for (int j=1;j<=m;j++)
    152             if (d[i][j])
    153             {
    154                 int index=i*(4*P*P)+j;      //带插入的列表下标。
    155                 if (!x[i])
    156                 {
    157                     row[i]=x[i]=index;
    158                 }
    159                 else
    160                 {
    161                     R[row[i]]=index;
    162                     L[index]=row[i];
    163                 }
    164                 D[col[j]]=index;
    165                 U[index]=col[j];
    166                 row[i]=col[j]=index;
    167                 C[index]=j;
    168                 S[j]++;
    169             }
    170     }
    171 
    172     for (int i=1;i<=n;i++)
    173         if (x[i])
    174         {
    175             L[x[i]]=row[i];
    176             R[row[i]]=x[i];
    177         }
    178     for (int j=1;j<=m;j++)
    179     {
    180         D[col[j]]=j;
    181         U[j]=col[j];
    182     }
    183 }
    184 
    185 int main()
    186 {
    187     //freopen("test.in","r+",stdin);
    188     //freopen("test.out","w+",stdout);
    189 
    190 
    191     n=P*P*P;
    192     m=4*P*P;
    193     memset(s,0,sizeof(s));
    194     while(scanf("%1s",&s[0][0])!=EOF)
    195     {
    196 
    197         for (int j=1;j<16;j++)
    198             scanf("%1s",&s[0][j]);
    199         for (int i=1;i<16;i++)
    200             for (int j=0;j<16;j++)
    201                 scanf("%1s",&s[i][j]);
    202         Link();
    203         Dance(0);
    204     }
    205     return 0;
    206 }
    POJ3076 套模板AC代码
      1 #include <cstdio>
      2 #include <cstring>
      3 #define inf 100000000
      4 #define N 256*16
      5 #define M 256*4
      6 #define MAX N*M
      7 int s[M],mat[N][M],ansq[N],u[MAX],d[MAX],l[MAX],r[MAX],c[MAX],row[MAX];
      8 int deep;
      9 void build(int n,int m)
     10 {
     11     r[0]=1;
     12     l[0]=m;
     13     for(int i=1; i<=m; i++)
     14     {
     15         l[i]=i-1;
     16         r[i]=(i+1)%(m+1);
     17         c[i]=d[i]=u[i]=i;
     18         s[i]=0;
     19     }
     20     int size=m;
     21     for(int i=1; i<=n; i++)
     22     {
     23         int rp=0;
     24         for(int j=1; j<=m; j++)
     25             if(mat[i-1][j-1])
     26             {
     27                 size++;
     28                 d[u[j]]=size;
     29                 u[size]=u[j];
     30                 d[size]=j;
     31                 u[j]=size;
     32                 if(!rp)
     33                 {
     34                     rp=size;
     35                     l[size]=size;
     36                     r[size]=size;
     37                 }
     38                 else
     39                 {
     40                     l[size]=l[rp];
     41                     r[size]=rp;
     42                     r[l[rp]]=size;
     43                     l[rp]=size;
     44                 }
     45                 c[size]=j;
     46                 row[size]=i;
     47                 s[j]++;
     48             }
     49     }
     50 }
     51 inline void remove(int pc)
     52 {
     53     r[l[pc]]=r[pc];
     54     l[r[pc]]=l[pc];
     55     for(int i=d[pc]; i!=pc; i=d[i])
     56         for(int j=r[i]; j!=i; j=r[j])
     57         {
     58             u[d[j]]=u[j];
     59             d[u[j]]=d[j];
     60             s[c[j]]--;
     61         }
     62 }
     63  
     64 inline void resume(int pc)
     65 {
     66     for(int i=u[pc]; i!=pc; i=u[i])
     67         for(int j=l[i]; j!=i; j=l[j])
     68         {
     69             d[u[j]]=j;
     70             u[d[j]]=j;
     71             s[c[j]]++;
     72         }
     73     l[r[pc]]=pc;
     74     r[l[pc]]=pc;
     75 }
     76  
     77 bool dfs(int dep)
     78 {
     79     if(!r[0])
     80     {
     81         deep = dep;
     82         return true;
     83     }
     84  
     85     int pc,mins=inf;
     86     for(int t=r[0]; t; t=r[t])
     87         if(mins>s[t])
     88         {
     89             mins=s[t];
     90             pc=t;
     91         }
     92     remove(pc);
     93     for(int i=d[pc]; i!=pc; i=d[i])
     94     {
     95         ansq[dep]=row[i]-1;
     96         for(int j=r[i]; j!=i; j=r[j])
     97             remove(c[j]);
     98         if(dfs(dep+1))
     99             return true;
    100         for(int j=l[i]; j!=i; j=l[j])
    101             resume(c[j]);
    102     }
    103     resume(pc);
    104     return false;
    105 }
    106 char str[20];
    107 char sudoku[17][17];
    108 int main()
    109 {
    110     while(1)
    111     {
    112         memset(mat,0,sizeof(mat));
    113         memset(ansq,0,sizeof(ansq));
    114         memset(sudoku,0,sizeof(sudoku));
    115         for(int i=0; i<16; i++)
    116         {
    117             if(scanf("%s",str)!=1)
    118                 return 0;
    119             for(int j=0; j<16; j++)
    120             {
    121                 if(str[j]=='-')
    122                 {
    123                     for(int k=0; k<16; k++)
    124                     {
    125                         mat[256*k+16*i+j][k*16+i]=1;
    126                         mat[256*k+16*i+j][256+k*16+j]=1;
    127                         mat[256*k+16*i+j][512+16*k+i/4*4+j/4]=1;
    128                         mat[256*k+16*i+j][768+i*16+j]=1;
    129                     }
    130                 }
    131                 else
    132                 {
    133                     mat[256*(str[j]-'A')+16*i+j][(str[j]-'A')*16+i]=1;
    134                     mat[256*(str[j]-'A')+16*i+j][256+(str[j]-'A')*16+j]=1;
    135                     mat[256*(str[j]-'A')+16*i+j][512+16*(str[j]-'A')+i/4*4+j/4]=1;
    136                     mat[256*(str[j]-'A')+16*i+j][768+i*16+j]=1;
    137                 }
    138             }
    139         }
    140         build(N,M);
    141         dfs(0);
    142         for(int i=0; i<deep; i++)
    143             sudoku[ansq[i]%256/16][ansq[i]%16]=ansq[i]/256+'A';
    144         for(int i=0; i<16; i++)
    145             printf("%s\n",sudoku[i]);
    146         printf("\n");
    147     }
    148     return 0;
    149 }

    HDU 4069  (好题~~~数独的变形---2011 ACM/ICPC Asia Regional Fuzhou Site —— Online Contest) 

    http://acm.hdu.edu.cn/showproblem.php?pid=4069

    原来不会判断多解。。。
    dfs的时候如果成功搜索两次,说明存在多解,
    成功搜索一次则存在唯一解,
    否则无解。
    用一个Floodfill预处理每一个格子所属块。
    HDU 4069
      1 #include <iostream>
      2 #include <cstdio>
      3 #include <cstdlib>
      4 #include <cmath>
      5 #include <iomanip>
      6 #include <climits>
      7 #include <vector>
      8 #include <stack>
      9 #include <queue>
     10 #include <set>
     11 #include <map>
     12 #include <algorithm>
     13 #include <string>
     14 #include <cstring>
     15 
     16 using namespace std;
     17 
     18 typedef long long LL;
     19 const double EPS = 1e-11;
     20 
     21 int s[10][10];
     22 int color[10][10];
     23 
     24 //Dancing Links
     25 //列(N+N+N)*N+N*N=4*N*N.
     26 #define N 750
     27 #define M 350
     28 const int P=9;  //p阶数独
     29 int h;
     30 int ans;        //判断多解
     31 int L[N*M],R[N*M],U[N*M],D[N*M],S[M],C[N*M],O[N];
     32 bool d[N][M];
     33 
     34 
     35 int n,m;
     36 inline void remove (const int &c)
     37 {
     38     L[R[c]]=L[c];
     39     R[L[c]]=R[c];
     40     for (int i=D[c];i!=c;i=D[i])
     41         for (int j=R[i];j!=i;j=R[j])
     42         {
     43             U[D[j]]=U[j];
     44             D[U[j]]=D[j];
     45             --S[C[j]];
     46         }
     47 }
     48 
     49 inline void resume (const int &c)
     50 {
     51     for (int i=U[c];i!=c;i=U[i])
     52         for (int j=L[i];j!=i;j=L[j])
     53         {
     54             U[D[j]]=j;
     55             D[U[j]]=j;
     56             ++S[C[j]];
     57         }
     58     L[R[c]]=c;
     59     R[L[c]]=c;
     60 }
     61 
     62 bool Dance(int k)
     63 {
     64     if (R[h]==h)
     65     {
     66         ans++;
     67         if (ans==2)
     68             return true;
     69         return false;
     70     }
     71 
     72     int c,ss=INT_MAX;
     73 
     74     for (int i=R[h];i!=h;i=R[i])
     75         if (S[i]<ss)
     76         {
     77             ss=S[i];
     78             c=i;
     79         }
     80 
     81     remove(c);
     82     for (int i=D[c];i!=c;i=D[i])
     83     {
     84         if (ans==0) O[k]=i;
     85         for (int j=R[i];j!=i;j=R[j])
     86             remove(C[j]);
     87         if (Dance(k+1))
     88             return true;
     89         for (int j=L[i];j!=i;j=L[j])
     90             resume(C[j]);
     91     }
     92     resume(c);
     93 
     94     return false;
     95 }
     96 
     97 //Initialize
     98 void Link()
     99 {
    100 
    101     memset(d,0,sizeof(d));
    102     memset(O,0,sizeof(O));
    103 
    104     //preprocess the sudoku 数独转换精确覆盖问题矩阵形式
    105     for (int i=1;i<=P;i++)
    106         for (int j=1;j<=P;j++)
    107         {
    108             if (s[i-1][j-1]==0)
    109             {
    110                 for (int k=1;k<=P;k++)
    111                 {
    112                     int rr=((i-1)*P+j-1)*P+k;                   //表示数独第i行第j列数填k
    113                     d[rr][(i-1)*P+k]=1;                         //表示数独第i行有数k
    114                     d[rr][(j-1)*P+k+P*P]=1;                     //表示数独第j行有数k
    115                     d[rr][(color[i-1][j-1]-1)*P+k+2*P*P]=1;     //表示数独第p个十六宫格有数k
    116                     d[rr][(i-1)*P+j+3*P*P]=1;                   //表示数独第i行第j行有一个数(防止一个格子填多个数)
    117                 }
    118             }
    119             else
    120             {
    121                 int num=s[i-1][j-1];
    122                 int rr=((i-1)*P+j-1)*P+num;                 //表示数独第i行第j列数填k
    123                 d[rr][(i-1)*P+num]=1;                       //表示数独第i行有数k
    124                 d[rr][(j-1)*P+num+P*P]=1;                   //表示数独第j行有数k
    125                 d[rr][(color[i-1][j-1]-1)*P+num+2*P*P]=1;      //表示数独第p个十六宫格有数k
    126                 d[rr][(i-1)*P+j+3*P*P]=1;                   //表示数独第i行第j行有一个数(防止一个格子填多个数)
    127             }
    128 
    129         }
    130 
    131     //Initialize the all matrix to list.
    132     int x[N],row[N],col[M];           //x表示当前行中的第一个链,row表示当前行中上一个插入的链、col表示当前列中上一个插入的链。
    133     h=0;
    134     for (int i=1;i<=m;i++)
    135     {
    136         R[i-1]=i;
    137         L[i]=i-1;
    138         S[i]=0;
    139         col[i]=i;
    140     }
    141     col[0]=0;
    142     L[h]=m;
    143     R[m]=h;
    144 
    145     for (int i=1;i<=n;i++)
    146     {
    147         x[i]=0;                             //行第一个链表
    148         for (int j=1;j<=m;j++)
    149             if (d[i][j])
    150             {
    151                 int index=i*(4*P*P)+j;      //带插入的列表下标。
    152                 if (!x[i])
    153                 {
    154                     row[i]=x[i]=index;
    155                 }
    156                 else
    157                 {
    158                     R[row[i]]=index;
    159                     L[index]=row[i];
    160                 }
    161                 D[col[j]]=index;
    162                 U[index]=col[j];
    163                 row[i]=col[j]=index;
    164                 C[index]=j;
    165                 S[j]++;
    166             }
    167     }
    168 
    169     for (int i=1;i<=n;i++)
    170         if (x[i])
    171         {
    172             L[x[i]]=row[i];
    173             R[row[i]]=x[i];
    174         }
    175     for (int j=1;j<=m;j++)
    176     {
    177         D[col[j]]=j;
    178         U[j]=col[j];
    179     }
    180 }
    181 
    182 int dr[4][2]={{-1,0},{0,1},{1,0},{0,-1}};
    183 int vis[10][10];
    184 int block[10][10][10][10];
    185 int nu;
    186 
    187 void dfs(int x,int y)
    188 {
    189     color[x][y]=nu;
    190     vis[x][y]=1;
    191     for (int i=0;i<4;i++)
    192     {
    193         int dx=x+dr[i][0];
    194         int dy=y+dr[i][1];
    195         if (!vis[dx][dy] && !block[dx][dy][x][y] && dx>=0 && dx<9 && dy>=0 && dy<9)
    196             dfs(dx,dy);
    197     }
    198 }
    199 
    200 int main()
    201 {
    202     //freopen("test.in","r+",stdin);
    203     //freopen("test.out","w+",stdout);
    204 
    205     int t;
    206     int caseo=1;
    207     scanf("%d",&t);
    208     n=P*P*P;
    209     m=4*P*P;
    210     memset(s,0,sizeof(s));
    211     while(t--)
    212     {
    213         memset(block,0,sizeof(block));
    214         memset(color,0,sizeof(color));
    215         memset(vis,0,sizeof(vis));
    216         ans=0;
    217         nu=1;
    218         for (int i=0;i<P;i++)
    219             for (int j=0;j<P;j++)
    220             {
    221                 scanf("%d",&s[i][j]);
    222                 if (s[i][j]>=128)
    223                 {
    224                     if (j>0)
    225                     {
    226                         block[i][j][i][j-1]=1;
    227                         block[i][j-1][i][j]=1;
    228                     }
    229                     s[i][j]-=128;
    230                 }
    231                 if (s[i][j]>=64)
    232                 {
    233                     if (i<8)
    234                     {
    235                         block[i][j][i+1][j]=1;
    236                         block[i+1][j][i][j]=1;
    237                     }
    238                     s[i][j]-=64;
    239                 }
    240                 if (s[i][j]>=32)
    241                 {
    242                     if (j<8)
    243                     {
    244                         block[i][j][i][j+1]=1;
    245                         block[i][j+1][i][j]=1;
    246                     }
    247 
    248                     s[i][j]-=32;
    249                 }
    250                 if (s[i][j]>=16)
    251                 {
    252                     if (i>0)
    253                     {
    254                         block[i][j][i-1][j]=1;
    255                         block[i-1][j][i][j]=1;
    256                     }
    257                     s[i][j]-=16;
    258                 }
    259             }
    260 
    261 
    262         for (int i=0;i<P;i++)
    263             for (int j=0;j<P;j++)
    264             {
    265                 if (!vis[i][j])
    266                 {
    267                     dfs(i,j);
    268                     nu++;
    269                 }
    270             }
    271         Link();
    272         Dance(0);
    273         printf("Case %d:\n",caseo++);
    274         if (ans==1)
    275         {
    276             sort(O,O+81);
    277             for (int i=0;i<81;i++)
    278             {
    279                 printf("%d",(O[i]-1)/m%P==0?P:((O[i]-1)/m%P));
    280                 if ((i+1)%P==0)
    281                     printf("\n");
    282             }
    283         }
    284         else if (ans==2)
    285             printf("Multiple Solutions\n");
    286         else
    287             printf("No solution\n");
    288     }
    289     return 0;
    290 }

    (未完待续。。。)

     

    举杯独醉,饮罢飞雪,茫然又一年岁。 ------AbandonZHANG
  • 相关阅读:
    iOS-MVC设计模式
    LoadRunner中文转码
    LoadRunner中Base64编码解码
    jmeter持续集成化(一)---jmeter+Ant+DOS构建执行脚本
    LoadRunner MD5加密
    Jmeter元件--BeanShell Timer
    ftp上传下载
    Shell编程实例
    Oracle数据库sqlplus操作
    oracle执行计划分析
  • 原文地址:https://www.cnblogs.com/AbandonZHANG/p/2660188.html
Copyright © 2011-2022 走看看