ZOJ_3209
精确覆盖问题,用Dancing Links直接求解即可。
#include<stdio.h> #include<string.h> #include<algorithm> #define MAXN 510 #define MAXM 910 #define MAXD 460010 #define INF 0x3f3f3f3f int N, M, P, size, U[MAXD], D[MAXD], L[MAXD], R[MAXD], C[MAXD]; int S[MAXM], H[MAXN], ANS, vis[MAXM]; void prep(int n, int m) { int i; for(i = 0; i <= m; i ++) { R[i] = i + 1, L[i + 1] = i; U[i] = D[i] = i; S[i] = 0; } R[m] = 0, size = m; memset(H, -1, sizeof(H[0]) * (n + 1)); } void insert(int r, int c) { ++ size; C[size] = c, ++ S[c]; D[size] = D[c], U[size] = 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 init() { int i, j, k, x1, x2, y1, y2; scanf("%d%d%d", &N, &M, &P); prep(P, N * M); for(k = 1; k <= P; k ++) { scanf("%d%d%d%d", &x1, &y1, &x2, &y2); for(i = x1; i < x2; i ++) for(j = y1; j < y2; j ++) insert(k, i * M + j + 1); } } 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]) D[U[j]] = D[j], U[D[j]] = U[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]) D[U[j]] = j, U[D[j]] = j, ++ S[C[j]]; R[L[c]] = c, L[R[c]] = c; } void dance(int dep) { if(R[0] == 0) { ANS = std::min(ANS, dep); return ; } int i, j, t = INF, id; for(i = R[0]; i != 0; i = R[i]) if(S[i] < t) t = S[i], id = i; remove(id); for(i = D[id]; i != id; i = D[i]) { for(j = R[i]; j != i; j = R[j]) remove(C[j]); dance(dep + 1); for(j = L[i]; j != i; j = L[j]) resume(C[j]); } resume(id); } void solve() { ANS = INF; dance(0); printf("%d\n", ANS == INF ? -1 : ANS); } int main() { int t; scanf("%d", &t); while(t --) { init(); solve(); } return 0; }