• POJ2676,HDU4069解决数独的两种实现:DFS、DLX


    搜索实现:解决数独有两种思考策略,一种是枚举当前格能填的数字的种数,这里有一优化策略就是先搜索能填入种数小的格子;另一种是考虑处理某一行(列、宫)时,对于某一个没用过的数字,若该行(列、宫)只有一个可行的空白格时,就只能将该数字填入此格中。第二种实现起来略麻烦,此处仅实现第一种策略,并调整搜索顺序进行优化操作,优先搜索能填数字种数较小的格子。

    另外,在搜索时,条件判断的效率尤为重要,故分别记录各行、各列、各宫已经出现的数字,这样就可以直接判断该空格填入某数字是否可行。

    以POJ2676为例,无调整搜索顺序的优化,用时26ms,调整搜索顺序后用时0ms。

     1 //dfs搜索,枚举当前格能填的数字
     2 #include <stdio.h>
     3 #include <algorithm>
     4 using namespace std;
     5 const int N = 9;
     6 char mp[N+1][N+1];
     7 int row[N+1], col[N+1], squ[N+1];
     8 struct p{
     9     int x, y, z;
    10     p(int a = 0, int b = 0, int c = 0) :x(a), y(b), z(c){}
    11     bool operator <(const p& m)const {
    12         return z < m.z;
    13     }
    14 };
    15 p pa[N*N+1];
    16 int tot;
    17 
    18 bool dfs(int d) {
    19     if (d == tot) return true;
    20 
    21     for(int i = d; i < tot; i++){
    22         int nn = 0, x = pa[i].x, y = pa[i].y;
    23         pa[i].z = 0;
    24         for(int j = 1; j < 512; j <<= 1)
    25             if( !(row[x]&j) && !(col[y]&j) && !(squ[x/3*3+y/3]&j) )
    26                 pa[i].z++;
    27     }
    28     sort(pa+d, pa+tot);//调整搜素顺序!!
    29 
    30     int x = pa[d].x, y = pa[d].y;
    31     for(int i = 1; i <= N; i++){
    32         int j = 1 <<(i-1);
    33         if(!(row[x]&j) && !(col[y]&j) && !(squ[x/3*3+y/3]&j)){
    34             row[x] ^= j, col[y] ^= j, squ[x/3*3+y/3] ^= j;
    35             mp[x][y] = '0'+i;
    36             if(dfs(d+1)) return true;
    37             row[x] ^= j, col[y] ^= j, squ[x/3*3+y/3] ^= j;
    38         }
    39     }
    40     return false;
    41 }
    42 
    43 int main(){
    44     int t; scanf("%d", &t);
    45     while(t--){
    46         for(int i = 0; i < 9; i++)
    47             for(int j = 0; j < 9; j++)
    48                 scanf(" %c", &mp[i][j]);
    49 
    50         for(int i = 0; i < N; i++)
    51             row[i] = col[i] = squ[i] = 0;
    52         tot = 0;
    53 
    54         for(int i = 0; i < N; i++)
    55             for(int j = 0; j < N; j++)
    56                 if(mp[i][j] != '0'){
    57                     int idx = mp[i][j]-'1';
    58                     row[i] |= 1<<idx, col[j] |= 1<<idx, squ[i/3*3+j/3] |= 1<<idx;
    59                 }
    60                 else
    61                     pa[tot++] = p(i, j);
    62 
    63         for(int i = 0; i < tot; i++){
    64             int nn = 0, x = pa[i].x, y = pa[i].y;
    65             for(int j = 1; j < 512; j <<= 1)
    66                 if( !(row[x]&j) && !(col[y]&j) && !(squ[x/3*3+y/3]&j) )
    67                     pa[i].z++;
    68         }
    69 
    70         dfs(0);
    71 
    72         for (int i = 0; i < 9; ++i)
    73             puts(mp[i]);
    74     }
    75     return 0;
    76 }
    View Code

    DLX算法的POJ2676

      1 //******************************************************//
      2 //输入T表示T组数据。                                    //
      3 //每组数据为9个长度为9的字符串,空白处以字符0替代。        //
      4 //POJ2676                                               //
      5 //******************************************************//
      6 
      7 #include <bits/stdc++.h>
      8 using namespace std;
      9 const int maxnode = 100010;
     10 const int MaxM = 1010;
     11 const int MaxN = 1010;
     12 struct DLX{
     13     int n, m, size;                 //行数,列数,总数
     14     int U[maxnode], D[maxnode], R[maxnode], L[maxnode], Row[maxnode], Col[maxnode];
     15     int H[MaxN], S[MaxM];           //S记录该列剩余1的个数,H表示该行最左端的1
     16     int ansd, ans[MaxN];
     17 
     18     void init(int _n, int _m){
     19         n = _n;
     20         m = _m;
     21         for(int i = 0; i <= m; i++){
     22             S[i] = 0;
     23             U[i] = D[i] = i;
     24             L[i] = i-1;
     25             R[i] = i+1;
     26         }
     27         R[m] = 0; L[0] = m;
     28         size = m;
     29         memset(H, -1, sizeof(H));
     30     }
     31     void Link(int r, int c){
     32         size++;
     33         Col[size] = c, Row[size] = r;
     34         S[c]++;
     35         U[size] = U[c], D[size] = c;
     36         D[U[c]] = size;
     37         U[c] = size;
     38         if (H[r] != -1) {
     39             R[size] = H[r] ;
     40             L[size] = L[H[r]] ;
     41             R[L[size]] = size ;
     42             L[R[size]] = size ;
     43         }
     44         else
     45             H[r] = L[size] = R[size] = size ;
     46     }
     47     void remove(int c){//覆盖第c列。删除第c列及能覆盖到该列的行,防止重叠
     48         L[R[c]] = L[c]; R[L[c]] = R[c];
     49         for(int i = D[c]; i != c; i = D[i])
     50             for(int j = R[i]; j != i; j = R[j]){
     51                 U[D[j]] = U[j];
     52                 D[U[j]] = D[j];
     53                 --S[Col[j]];
     54             }
     55     }
     56     void resume(int c){
     57         for(int i = U[c]; i != c; i = U[i])
     58             for(int j = L[i]; j != i; j = L[j]){
     59                 ++ S[Col[j]];
     60                 U[D[j]] = j;
     61                 D[U[j]] = j;
     62             }
     63         L[R[c]] = R[L[c]] = c;
     64     }
     65     //d为递归深度
     66     bool dance(int d){
     67         if(R[0] == 0){
     68             ansd = d;
     69             return true;
     70         }
     71         int c = R[0];
     72         for(int i = R[0]; i != 0; i = R[i])
     73             if(S[i] < S[c])
     74                 c = i;
     75         remove(c);
     76         for(int i = D[c];i != c;i = D[i]){
     77             ans[d] = Row[i];
     78             for(int j = R[i]; j != i; j = R[j]) remove(Col[j]);
     79             if(dance(d+1)) return true;
     80             for(int j = L[i]; j != i; j = L[j]) resume(Col[j]);
     81         }
     82         resume(c);
     83         return false;
     84     }
     85 };
     86 DLX g;
     87 char s[15][15];
     88 int main(){
     89     int t;
     90     scanf("%d", &t);
     91     while(t--){
     92         for(int i = 0; i < 9; i++)
     93             scanf("%s", s[i]);
     94 
     95         g.init(81*9, 81+81+81+81);
     96 
     97         for(int i = 0; i < 9; i++)
     98             for(int j = 0; j < 9; j++){
     99                 int x = i, y = j, z = x/3*3+y/3, w = i*9+j;
    100                 if(s[i][j] == '0'){
    101                     for(int k = 1; k <= 9; k++){
    102                         g.Link(w*9+k, w+1);
    103                         g.Link(w*9+k, 81+x*9+k);
    104                         g.Link(w*9+k, 162+y*9+k);
    105                         g.Link(w*9+k, 243+z*9+k);
    106                     }
    107                 }
    108                 else {
    109                     int t = s[i][j]-'0';
    110                     g.Link(w*9+t, w+1);
    111                     g.Link(w*9+t, 81+x*9+t);
    112                     g.Link(w*9+t, 162+y*9+t);
    113                     g.Link(w*9+t, 243+z*9+t);
    114                 }
    115             }
    116         g.dance(0);
    117 
    118         for(int i = 0; i < g.ansd; i++){
    119             int t = g.ans[i];
    120             int a = (t-1)/9, b = (t-1)%9+'1';
    121             s[a/9][a%9] = b;
    122         }
    123         for(int i = 0; i < 9; i++)
    124             puts(s[i]);
    125     }
    126     return 0;
    127 }
    View Code

    DLX算法很容易,套个框架就能解决了,还能高效解决变形数独。用HDU4069,一个变形数独为例。

      1 //******************************************************//
      2 //hdu4069                                               //
      3 //******************************************************//
      4 #include <bits/stdc++.h>
      5 using namespace std;
      6 const int MaxM = 1000+10;
      7 const int MaxN = 1000+10;
      8 const int maxnode = MaxM*MaxN;
      9 struct DLX{
     10     int n, m, size;                 //行数,列数,总数
     11     int U[maxnode], D[maxnode], R[maxnode], L[maxnode], Row[maxnode], Col[maxnode];
     12     int H[MaxN], S[MaxM];           //S记录该列剩余1的个数,H表示该行最左端的1
     13     int ansd, ans[MaxN];
     14     int temp[MaxN];
     15     int tot;
     16 
     17     void init(int _n, int _m){
     18         n = _n;
     19         m = _m;
     20         for(int i = 0; i <= m; i++){
     21             S[i] = 0;
     22             U[i] = D[i] = i;
     23             L[i] = i-1;
     24             R[i] = i+1;
     25         }
     26         R[m] = 0; L[0] = m;
     27         size = m;
     28         memset(H, -1, sizeof(H));
     29 
     30         tot = 0;
     31     }
     32     void Link(int r, int c){
     33         size++;
     34         Col[size] = c, Row[size] = r;
     35         S[c]++;
     36         U[size] = U[c], D[size] = c;
     37         D[U[c]] = size;
     38         U[c] = size;
     39         if (H[r] != -1) {
     40             R[size] = H[r] ;
     41             L[size] = L[H[r]] ;
     42             R[L[size]] = size ;
     43             L[R[size]] = size ;
     44         }
     45         else
     46             H[r] = L[size] = R[size] = size ;
     47     }
     48     void remove(int c){//覆盖第c列。删除第c列及能覆盖到该列的行,防止重叠
     49         L[R[c]] = L[c]; R[L[c]] = R[c];
     50         for(int i = D[c]; i != c; i = D[i])
     51             for(int j = R[i]; j != i; j = R[j]){
     52                 U[D[j]] = U[j];
     53                 D[U[j]] = D[j];
     54                 --S[Col[j]];
     55             }
     56     }
     57     void resume(int c){
     58         for(int i = U[c]; i != c; i = U[i])
     59             for(int j = L[i]; j != i; j = L[j]){
     60                 ++ S[Col[j]];
     61                 U[D[j]] = j;
     62                 D[U[j]] = j;
     63             }
     64         L[R[c]] = R[L[c]] = c;
     65     }
     66     //d为递归深度
     67     int dance(int d){
     68         if(R[0] == 0){
     69             ansd = d;
     70             for(int i = 0; i < ansd; i++)
     71                 ans[i] = temp[i];
     72             tot++;
     73             return tot;
     74         }
     75         int c = R[0];
     76         for(int i = R[0]; i != 0; i = R[i])
     77             if(S[i] < S[c])
     78                 c = i;
     79         remove(c);
     80         for(int i = D[c];i != c;i = D[i]){
     81             temp[d] = Row[i];
     82             for(int j = R[i]; j != i; j = R[j]) remove(Col[j]);
     83             if(dance(d+1) > 1) return tot;
     84             for(int j = L[i]; j != i; j = L[j]) resume(Col[j]);
     85         }
     86         resume(c);
     87         return tot;
     88     }
     89 };
     90 DLX g;
     91 
     92 int a[10][10];
     93 int gird[10][10];
     94 int d[4][2] = {{-1,0},{0,1},{1,0},{0,-1}};//u,r,d,l
     95 void dfs(int x, int y, int color){
     96     gird[x][y] = color;
     97     for(int i = 0; i < 4; i++){
     98         int xx = x+d[i][0], yy = y+d[i][1];
     99         if((a[x][y] & (16<<i))== 0&&xx >= 0&& xx < 9&&yy >= 0&&yy <9&&gird[xx][yy] == -1)
    100             dfs(xx, yy, color);
    101     }
    102     return ;
    103 }
    104 
    105 int main(){
    106     int T; scanf("%d", &T);
    107     for(int ca = 1; ca <= T; ca++){
    108         for(int i = 0; i < 9; i++)
    109             for(int j = 0; j < 9; j++)
    110                 scanf("%d", &a[i][j]);
    111         memset(gird, -1, sizeof(gird));
    112         int tt = 0;
    113         for(int i = 0; i < 9; i++)
    114             for(int j = 0; j < 9; j++)
    115                 if(gird[i][j] == -1) dfs(i, j, tt++);
    116 
    117         g.init(81*9, 81*4);
    118         for(int i = 0; i < 9; i++)
    119             for(int j = 0; j < 9; j++){
    120                 int t = (a[i][j]&15), w = i*9+j, x = i, y = j, z = gird[i][j];
    121                 if(t){
    122                     g.Link(w*9+t, w+1);
    123                     g.Link(w*9+t, 81+x*9+t);
    124                     g.Link(w*9+t, 162+y*9+t);
    125                     g.Link(w*9+t, 243+z*9+t);
    126                 }else {
    127                     for(int k = 1; k <= 9; k++){
    128                         g.Link(w*9+k, w+1);
    129                         g.Link(w*9+k, 81+x*9+k);
    130                         g.Link(w*9+k, 162+y*9+k);
    131                         g.Link(w*9+k, 243+z*9+k);
    132                     }
    133                 }
    134             }
    135 
    136         printf("Case %d:
    ", ca);
    137         int ret = g.dance(0);
    138         if(ret == 1){
    139             for(int i = 0; i < g.ansd; i++){
    140                 int t = g.ans[i];
    141                 int x = (t-1)/9, y = (t-1)%9+1;
    142                 a[x/9][x%9] = y;
    143             }
    144             for(int i = 0; i < 9; i++){
    145                 for(int j = 0; j < 9; j++)
    146                     printf("%d", a[i][j]);
    147                 puts("");
    148             }
    149         }
    150         else if(ret > 1) puts("Multiple Solutions");
    151         else puts("No solution");
    152     }
    153     return 0;
    154 }
    View Code
    诸神对凡人心生艳羡,厌倦天堂。
  • 相关阅读:
    C#秘密武器之表达式树
    C#秘密武器之特性
    [转]拷贝构造函数详解
    [转]STL 容器一些底层机制
    C++ Qt多线程 TcpSocket服务器实例
    QByteArray储存二进制数据(包括结构体,自定义QT对象)
    [转]浅谈 C++ 中的 new/delete 和 new[]/delete[]
    [转]QList内存释放
    Subscribe的第四个参数用法
    ROS多线程订阅消息
  • 原文地址:https://www.cnblogs.com/dirge/p/5206730.html
Copyright © 2020-2023  润新知