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("\n"); 201 } 202 return 0; 203 }