POJ3074 Sudoku —— Dancing Links 精确覆盖

题目链接:http://poj.org/problem?id=3074


 

Sudoku
Time Limit: 1000MS   Memory Limit: 65536K
Total Submissions: 10451   Accepted: 3776

 

Description

In the game of Sudoku, you are given a large 9 × 9 grid divided into smaller 3 × 3 subgrids. For example,

. 2 7 3 8 . . 1 .
. 1 . . . 6 7 3 5
. . . . . . . 2 9
3 . 5 6 9 2 . 8 .
. . . . . . . . .
. 6 . 1 7 4 5 . 3
6 4 . . . . . . .
9 5 1 8 . . . 7 .
. 8 . . 6 5 3 4 .

Given some of the numbers in the grid, your goal is to determine the remaining numbers such that the numbers 1 through 9 appear exactly once in (1) each of nine 3 × 3 subgrids, (2) each of the nine rows, and (3) each of the nine columns.

Input

The input test file will contain multiple cases. Each test case consists of a single line containing 81 characters, which represent the 81 squares of the Sudoku grid, given one row at a time. Each character is either a digit (from 1 to 9) or a period (used to indicate an unfilled square). You may assume that each puzzle in the input will have exactly one solution. The end-of-file is denoted by a single line containing the word “end”.

Output

For each test case, print a line representing the completed Sudoku puzzle.

Sample Input

.2738..1..1...6735.......293.5692.8...........6.1745.364.......9518...7..8..6534.
......52..8.4......3...9...5.1...6..2..7........3.....6...1..........7.4.......3.
end

Sample Output

527389416819426735436751829375692184194538267268174593643217958951843672782965341
416837529982465371735129468571298643293746185864351297647913852359682714128574936

Source

 



题解:

Dancing Links博客(来自万仓一黍 )

Dancing Links的一些特点:

1.矩阵中每个元素的值只能是0或1(在实际操作中只记录1)。

2.行代表着放置情况, 列代表着约束条件。其中矩阵中的行和列的编号从1开始。

3.选择若干行,使得其满足所有约束条件。


对于此题:

1.行:9*9*9,表明有9*9个格子,每个格子有9中情况。

2.列:9*9*4,首先每个格子能且仅能放1个数字,其次每一行的九个数字能且仅能被放一次, 再者列如行者,最后每个九宫格的九个数字能且仅能被放一次。

3.所以构成了(9*9*9) * (9*9*4)的矩阵,然后直接套模板。



代码如下:

  1 #include <iostream>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <cmath>
  5 #include <algorithm>
  6 #include <vector>
  7 #include <queue>
  8 #include <stack>
  9 #include <map>
 10 #include <string>
 11 #include <set>
 12 #define ms(a,b) memset((a),(b),sizeof((a)))
 13 using namespace std;
 14 typedef long long LL;
 15 const int N = 9;
 16 const int MaxN = N*N*N+10;
 17 const int MaxM = N*N*4+10;
 18 const int maxnode = MaxN*4 + MaxM + 10;
 19 
 20 char g[MaxN];
 21 struct DLX      //矩阵的行和列是从1开始的
 22 {
 23     int n, m, size; //size为结点数
 24     int U[maxnode], D[maxnode], L[maxnode], R[maxnode], Row[maxnode], Col[maxnode];
 25     int H[MaxN], S[MaxM];   //H为每一行的头结点,但不参与循环。S为每一列的结点个数
 26     int ansd, ans[MaxN];
 27 
 28     void init(int _n, int _m)   //m为列
 29     {
 30         n = _n;
 31         m = _m;
 32         for(int i = 0; i<=m; i++)   //初始化列的头结点
 33         {
 34             S[i] = 0;
 35             U[i] = D[i] = i;
 36             L[i] = i-1;
 37             R[i] = i+1;
 38         }
 39         R[m] = 0; L[0] = m;
 40         size = m;
 41         for(int i = 1; i<=n; i++) H[i] = -1;    //初始化行的头结点
 42     }
 43 
 44     void Link(int r, int c)
 45     {
 46         size++; //类似于前向星
 47         Col[size] = c;
 48         Row[size] = r;
 49         S[Col[size]]++;
 50         D[size] = D[c];
 51         U[D[c]] = size;
 52         U[size] = c;
 53         D[c] = size;
 54         if(H[r]==-1) H[r] = L[size] = R[size] = size; //当前行为空
 55         else        //当前行不为空: 头插法,无所谓顺序,因为Row、Col已经记录了位置
 56         {
 57             R[size] = R[H[r]];
 58             L[R[H[r]]] = size;
 59             L[size] = H[r];
 60             R[H[r]] = size;
 61         }
 62     }
 63 
 64     void remove(int c)  //c是列的编号, 不是结点的编号
 65     {
 66         L[R[c]] = L[c]; R[L[c]] = R[c];     //在列的头结点的循环队列中, 越过列c
 67         for(int i = D[c]; i!=c; i = D[i])
 68         for(int j = R[i]; j!=i; j = R[j])
 69         {
 70             //被删除结点的上下结点仍然有记录
 71             U[D[j]] = U[j];
 72             D[U[j]] = D[j];
 73             S[Col[j]]--;
 74         }
 75     }
 76 
 77     void resume(int c)
 78     {
 79         L[R[c]] = R[L[c]] = c;
 80         for(int i = U[c]; i!=c; i = U[i])
 81         for(int j = L[i]; j!=i; j = L[j])
 82         {
 83             U[D[j]] = D[U[j]] = j;
 84             S[Col[j]]++;
 85         }
 86     }
 87 
 88     bool Dance(int d)
 89     {
 90         if(R[0]==0)
 91         {
 92             for(int i = 0; i<d; i++) g[(ans[i]-1)/9] = (ans[i]-1)%9 + '1';
 93             for(int i = 0; i<N*N; i++) printf("%c", g[i]);
 94             printf("\n");
 95             return true;
 96         }
 97 
 98         int c = R[0];
 99         for(int i = R[0]; i!=0; i = R[i])   //挑结点数最少的那一列,否则会超时,那为什么呢?
100             if(S[i]<S[c])
101                 c = i;
102 
103         remove(c);
104         for(int i = D[c]; i!=c; i = D[i])
105         {
106             ans[d] = Row[i];
107             for(int j = R[i]; j!=i; j = R[j]) remove(Col[j]);
108             if(Dance(d+1)) return true;
109             for(int j = L[i]; j!=i; j = L[j]) resume(Col[j]);
110         }
111         resume(c);
112         return false;
113     }
114 };
115 
116 //i、j从0开始,代表着位置; k从1开始,代表着数字
117 void place(int &r, int &c1, int &c2,int &c3, int &c4, int i, int j, int k)
118 {
119     //c1为每个格子一个数, c2为行, c3为列, c4为九宫格
120     r = (i*N+j)*N+k; c1 = i*N+j+1; c2 = N*N+i*N+k;
121     c3 = N*N*2+j*N+k; c4 = N*N*3+((i/3)*3+(j/3))*N+k;
122 }
123 
124 DLX dlx;
125 int main()
126 {
127     while(scanf("%s", g) && strcmp(g,"end") )
128     {
129         dlx.init(N*N*N, N*N*4);
130         int r, c1, c2, c3,c4;
131         for(int i = 0; i<N; i++)
132             for(int j = 0; j<N; j++)
133                 for(int k = 1; k<=N; k++)
134                 if(g[i*N+j]=='.' || g[i*N+j]=='0'+k)
135                 {
136                     place(r,c1,c2,c3,c4,i,j,k); //获取位置
137                     dlx.Link(r,c1);     //加入到矩阵中, 下同
138                     dlx.Link(r,c2);
139                     dlx.Link(r,c3);
140                     dlx.Link(r,c4);
141                 }
142         dlx.Dance(0);      //一起摇摆
143     }
144     return 0;
145 }
View Code

 

posted on 2017-09-16 09:58  h_z_cong  阅读(235)  评论(0编辑  收藏  举报

导航