poj 3074

题意:解数独

分析:

完整的数独有四个充要条件:

1.每个格子都有填数字

2.每列都有1~9中的每个数字

3.每行都有1~9中的每个数字

4.每个9宫格都有1~9中的每个数字

可以转化成精确覆盖问题。每行表示一个格子的一种填法,1~81列表示这个格子的位置,82~162列表示这是哪一行的什么数字,163~243列表示这是哪一列的什么数字,244~324列表示这是哪一个九宫格里的什么数字。每行都把四个1填入这四个区间里的对应位置。最后求出这个01矩阵的精确覆盖就是解。

在DFS里删除列的顺序为由左往右时TLE了,由右向左却AC,什么原因???

  1 #include <cstdio>
  2 #include <cstring>
  3 int U[240005],D[240005],L[240005],R[240005],row[800],col[800],cont[800];
  4 int X[240005],Y[240005],H[800],S[350],M,N,sz,ans[9][9];
  5 bool hashr[10][10],hashc[10][10],hashp[10][10];
  6 void init(int m)
  7 {
  8     for(int i = 0;i <= m;i++)
  9     {
 10         U[i] = D[i] = i;
 11         L[i + 1] = i;
 12         R[i] = i + 1;
 13         S[i] = 0;
 14     }
 15     R[m] = 0;
 16     L[0] = m;
 17     sz = m + 1;
 18 }
 19 
 20 void remove(int c)
 21 {
 22     //删除一整列
 23     R[L[c]] = R[c];
 24     L[R[c]] = L[c];
 25     //删除行
 26     for(int i = D[c];i != c;i = D[i])
 27     {
 28         for(int j = R[i];j != i;j = R[j])
 29         {
 30             D[U[j]] = D[j];
 31             U[D[j]] = U[j];
 32             S[X[j]]--;
 33         }
 34     }
 35 }
 36 
 37 void resume(int c)
 38 {
 39     //恢复一整列
 40     L[R[c]] = c;
 41     R[L[c]] = c;
 42     //恢复行
 43     for(int i = U[c];i != c;i = U[i])
 44     {
 45         for(int j = L[i];j != i;j = L[j])
 46         {
 47             D[U[j]] = j;
 48             U[D[j]] = j;
 49             S[X[j]]++;
 50         }
 51     }
 52 }
 53 
 54 void ins(int r,int c)
 55 {
 56     S[c]++;
 57     //纵向插入
 58     D[U[c]] = sz;
 59     U[sz] = U[c];
 60     D[sz] = c;
 61     U[c] = sz;
 62     X[sz] = c;
 63     Y[sz] = r;
 64     //横向插入
 65     if(H[r] == -1)
 66     {
 67         H[r] = L[sz] = R[sz] = sz;
 68     }
 69     else
 70     {
 71         R[L[H[r]]] = sz;
 72         L[sz] = L[H[r]];
 73         R[sz] = H[r];
 74         L[H[r]] = sz;
 75     }
 76     sz++;
 77 }
 78 
 79 bool dfs(int k)
 80 {
 81     if(R[0] == 0)
 82     {
 83         return true;
 84     }
 85     else
 86     {
 87         int m = 0xfffffff,num;
 88         for(int i = R[0];i != 0;i = R[i])
 89         {
 90             if(S[i] == 0)
 91             {
 92                 return false;
 93             }
 94             if(m > S[i])
 95             {
 96                 m = S[i];
 97                 num = i;
 98                 if(m == 1)
 99                 {
100                     break;
101                 }
102             }
103         }
104         remove(num);
105         for(int i = D[num];i != num;i = D[i])
106         {
107             ans[row[Y[i]]][col[Y[i]]] = cont[Y[i]];
108             for(int j = R[i];j != i;j = R[j])
109             {
110                 remove(X[j]);
111             }
112             if(dfs(k + 1))
113             {
114                 return true;
115             }
116             for(int j = L[i];j != i;j = L[j])//恢复顺序改为由左向右居然慢N倍?!
117             {
118                 resume(X[j]);
119             }
120         }
121         resume(num);
122     }
123     return false;
124 }
125 
126 int main()
127 {
128     char input[90];
129     while(scanf("%s",input),input[0] != 'e')
130     {
131         memset(hashr,false,sizeof(hashr));
132         memset(hashc,false,sizeof(hashc));
133         memset(hashp,false,sizeof(hashp));
134         for(int i = 0;i < 9;i++)
135         {
136             for(int j = 0;j < 9;j++)
137             {
138                 if(input[i * 9 + j] != '.')
139                 {
140                     hashr[i][input[i * 9 + j] - '0'] = true;
141                     hashc[j][input[i * 9 + j] - '0'] = true;
142                     hashp[i / 3 * 3 + j / 3][input[i * 9 + j] - '0'] = true;
143                 }
144             }
145         }
146         M = 4 * 9 * 9;
147         N = 0;
148         init(M);
149         for(int i = 0;i < 9;i++)
150         {
151             for(int j = 0;j < 9;j++)
152             {
153                 int k;
154                 if(input[i * 9 + j] != '.')
155                 {
156                     k = input[i * 9 + j] - '0';
157                 }
158                 else
159                 {
160                     k = 0;
161                 }
162                 if(k != 0)
163                 {
164                     row[N] = i;
165                     col[N] = j;
166                     cont[N] = k;
167                     H[N] = -1;
168                     ins(N,i * 9 + j + 1);//(i,j)位置已填数字
169                     ins(N,81 + i * 9 + k);//i行已有k
170                     ins(N,162 + j * 9 + k);//j列已有k
171                     ins(N++,243 + (i / 3 * 3 + j / 3) * 9 + k);//宫格已有k
172                 }
173                 else
174                 {
175                     for(k = 1;k <= 9;k++)
176                     {
177                         if(!hashr[i][k] && !hashc[j][k] && !hashp[i / 3 * 3 + j / 3][k])
178                         {
179                             row[N] = i;
180                             col[N] = j;
181                             cont[N] = k;
182                             H[N] = -1;
183                             ins(N,i * 9 + j + 1);//(i,j)位置已填数字
184                             ins(N,81 + i * 9 + k);//i行已有k
185                             ins(N,162 + j * 9 + k);//j列已有k
186                             ins(N++,243 + (i / 3 * 3 + j / 3) * 9 + k);//宫格已有k
187                         }
188                     }
189                 }
190             }
191         }
192         dfs(0);
193         for(int i = 0;i < 9;i++)
194         {
195             for(int j = 0;j < 9;j++)
196             {
197                 printf("%d",ans[i][j]);
198             }
199         }
200         printf("
");
201     }
202     return 0;
203 }
原文地址:https://www.cnblogs.com/ZShogg/p/3290922.html