HDU_4069

记得前一天我还在群里讨论数独的事情,才知道了又dancing links这么一回事,结果第二天的福州网赛居然就出了一个数独……

学了Dancing Links之后终于把这个题目A掉了,这个题目与普通的数独不同之处就在于分组的问题,以前是一个小九宫里不能重复1-9,而这次的形状是不规则的,需要先用深搜将图分成9个小组,再进行进一步的处理。

#include<stdio.h>
#include<string.h>
#define INF 1000000000
const int N = 9;
const int mn = N * N * N * 4 + N * N * 4 + N;
const int nn = N * N * 4 + N;
int U[mn], D[mn], L[mn], R[mn], C[mn], H[mn], X[mn];
int S[nn], Q[nn], visc[nn], size;
int a[nn][nn], ans[nn][nn], color[nn][nn], col, vis[nn][nn], num;
int dx[] = {-1, 1, 0, 0}, dy[] = {0 , 0, -1, 1}, wall[] = {16, 64, 128, 32};
void dfs(int x, int y)
{
int i, newx, newy;
for(i = 0; i < 4; i ++)
{
newx = x + dx[i];
newy = y + dy[i];
if(newx >= 0 && newx < N && newy >= 0 && newy < N
&& !vis[newx][newy] && !(wall[i] & a[x][y]))
{
vis[newx][newy] = 1;
color[newx][newy] = col ++;
dfs(newx, newy);
}
}
}
void prepare(int r, int c)
{
int i;
for(i = 0; i <= c; i ++)
{
S[i] = 0;
U[i] = D[i] = i;
R[i] = i + 1;
L[i + 1] = i;
}
R[c] = 0;
size = c;
while(r)
H[r --] = -1;
}
void place(int &r, int &c1, int &c2, int &c3, int &c4, int i, int j, int k)
{
r = (i * N + j) * N + k;
c1 = i * N + j + 1;
c2 = N * N + i * N + k;
c3 = 2 * N * N + j * N + k;
c4 = 3 * N * N + (color[i][j] / 10) * N + k;
}
void link (int r, int c)
{
size ++;
C[size] = c;
S[c] ++;
X[size] = r;
D[size] = D[c];
U[D[c]] = size;
U[size] = c;
D[c] = size;
if(H[r] < 0)
H[r] = L[size] = R[size] = size;
else
{
R[size] = R[H[r]];
L[R[H[r]]] = size;
L[size] = H[r];
R[H[r]] = size;
}
}
void init()
{
int i, j, k, r, c1, c2, c3, c4;
for(i = 0; i < N; i ++)
for(j = 0; j < N; j ++)
scanf("%d", &a[i][j]);
memset(vis, 0, sizeof(vis));
col = 0;
for(i = 0; i < N; i ++)
for(j = 0; j < N; j ++)
if(!vis[i][j])
{
vis[i][j] = 1;
color[i][j] = col ++;
dfs(i , j);
col ++;
}
prepare(mn, N * N * 4);
memset(visc, 0, sizeof(visc));
for(i = 0; i < N; i ++)
for(j = 0; j < N; j ++)
if(a[i][j] & 15)
{
place(r, c1, c2, c3, c4, i, j, a[i][j] & 15);
link(r, c1), link(r, c2), link(r, c3), link(r, c4);
visc[c2] = visc[c3] = visc[c4] = 1;
}
for(i = 0; i < N; i ++)
for(j = 0; j < N; j ++)
if(!(a[i][j] & 15))
for(k = 1; k <= N; k ++)
{
place(r, c1, c2, c3, c4, i, j, k);
if(visc[c2] || visc[c3] || visc[c4])
continue;
link(r, c1), link(r, c2), link(r, c3), link(r, c4);
}
}
void remove(int c)
{
int i, j;
R[L[c]] = R[c];
L[R[c]] = L[c];
for(i = D[c]; i != c; i = D[i])
for(j = R[i]; j != i; j = R[j])
{

U[D[j]] = U[j];
D[U[j]] = D[j];
S[C[j]] --;
}
}
void resume(int c)
{
int i, j;
for(i = U[c]; i != c; i = U[i])
for(j = L[i]; j != i; j = L[j])
{
S[C[j]] ++;
U[D[j]] = j;
D[U[j]] = j;
}
L[R[c]] = c;
R[L[c]] = c;
}
int dance(int cur)
{
int i, j, c,temp;
if(!R[0])
{
num ++;
if(num == 2)
return 1;
for(i = 0; i < cur; i ++)
{
int x = (X[Q[i]] - 1) / N / N;
int y = (X[Q[i]] - 1) / N % N;
ans[x][y] = (X[Q[i]] - 1) % N + 1;
}
return 0;
}
temp = INF;
for(i = R[0]; i != 0; i = R[i])
if(S[i] < temp)
{
c = i;
temp = S[i];
}
remove(c);
for(i = D[c]; i != c; i = D[i])
{
Q[cur] = i;
for(j = R[i]; j != i; j = R[j])
remove(C[j]);
if(dance(cur + 1))
return 1;
for(j = L[i]; j != i; j = L[j])
resume(C[j]);
}
resume(c);
return 0;
}
void printresult()
{
int i, j;
for(i = 0; i < N; i ++)
{
for(j = 0; j < N; j ++)
printf("%d", ans[i][j]);
printf("\n");
}
}
int main()
{
int t, tt;
scanf("%d", &t);
for(tt = 0; tt < t; tt ++)
{
init();
printf("Case %d:\n", tt + 1);
num = 0;
if(dance(0))
printf("Multiple Solutions\n");
else if(num == 1)
printresult();
else
printf("No solution\n");
}
return 0;
}


posted on 2011-10-10 16:40  Staginner  阅读(502)  评论(0编辑  收藏  举报