UVA_10160
这个题目我改下一下Dancing Links的算法,没想到搜过去了,只不过时间花的比较多。
由于原本Dancing Links是解决精确覆盖问题的,而这个问题是可以重复覆盖的,所以要把Dancing Links的删除和恢复的操作改变一下。
当然,还有更高效的搜索方式,可以google一下。
#include<stdio.h>
#include<string.h>
#define INF 0x3f3f3f3f
const int MAXN = 40;
const int MAXD = MAXN * MAXN + MAXN;
int U[MAXD], D[MAXD], L[MAXD], R[MAXD], C[MAXD], H[MAXN], S[MAXN];
int vis[MAXN], del[MAXN][MAXN], N, M, Min, size, g[MAXN][MAXN];
void prepare(int r, int c)
{
int i;
for(i = 0; i <= c; i ++)
{
U[i] = D[i] = i;
L[i + 1] = i, R[i] = i + 1;
S[i] = 0;
}
R[c] = 0;
while(r)
H[r --] = -1;
size = c;
}
void insert(int r, int c)
{
++ size;
C[size] = c;
++ S[c];
U[size] = c;
D[size] = D[c];
U[D[c]] = size;
D[c] = size;
if(H[r] == -1)
H[r] = L[size] = R[size] = size;
else
{
L[size] = H[r];
R[size] = R[H[r]];
L[R[H[r]]] = size;
R[H[r]] = size;
}
}
void remove(int c)
{
R[L[c]] = R[c];
L[R[c]] = L[c];
}
void resume(int c)
{
R[L[c]] = c;
L[R[c]] = c;
}
void dance(int cur)
{
int i, j, c, min = INF;
if(!R[0])
{
if(cur < Min)
Min = cur;
return ;
}
if(cur >= Min - 1)
return ;
for(i = R[0]; i != 0; i = R[i])
if(S[i] < min)
{
min = S[i];
c = i;
}
del[cur][c] = vis[c] = 1;
remove(c);
for(i = D[c]; i != c; i = D[i])
{
for(j = R[i]; j != i; j = R[j])
if(!vis[C[j]])
{
vis[C[j]] = del[cur][C[j]] = 1;
remove(C[j]);
}
dance(cur + 1);
for(j = L[i]; j != i; j = L[j])
if(del[cur][C[j]])
{
resume(C[j]);
vis[C[j]] = del[cur][C[j]] = 0;
}
}
resume(c);
del[cur][c] = vis[c] = 0;
}
void solve()
{
int i, j, k, x, y;
prepare(N, N);
memset(g, 0, sizeof(g));
for(i = 1; i <= N; i ++)
g[i][i] = 1;
for(i = 0; i < M; i ++)
{
scanf("%d%d", &x, &y);
g[x][y] = g[y][x] = 1;
}
for(i = 1; i <= N; i ++)
for(j = 1; j <= N; j ++)
if(g[i][j])
insert(i, j);
Min = INF;
memset(del, 0, sizeof(del));
memset(vis, 0, sizeof(vis));
dance(0);
printf("%d\n", Min);
}
int main()
{
for(;;)
{
scanf("%d%d", &N, &M);
if(!N && !M)
break;
solve();
}
return 0;
}