ZOJ Treasure Map DLX 精确覆盖
http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=3372
题意:
给你一个n*m的大矩形,然后给你p个小矩形,让你从中选出若干小矩形填满这个大矩形,这里保证所选的小矩形不存在相互覆盖。
思路:
才开始看到大牛的dlx分类里面看了之后,没什么想法,可能就做了一个题的原因把。说是把整个大矩形的面积看n*m的作列,每个小矩形看作行,然后拆出他所能覆盖的列然后问题就转化成了DLX问题了。
吐槽以下,这题我交了34遍啊。才开始自己想到了怎么写了就写了一下,中间出现各种错误, i : x1 到 x2 - 1 j: y1 + 1 到 y2 转化为本行所能覆盖的列时乘错了 i*tm + j才对,我给乘成tn了。还有就是初始化l,r,u,d,s,c时开始写的太搓了,后来又借鉴了一下写的不错的。 但是还是tle 个都无语了。。后来把恢复的顺序改为删除的顺序的相反顺序就A了。网上几乎都是按删除顺序的相反顺序恢复的,我个人觉得应该没问题啊,而且hust的那道模板题目也能过啊,不明白,希望有人指教。。谢谢了。。后来重新整理了一下模板。
View Code
#include <cstdio> #include <cstring> #include <iostream> #define CL(a,num) memset((a),(num),sizeof(a)) #define inf 0x7f7f7f7f #define M 907 #define N 450024 using namespace std; const int head = 0; int l[N],r[N],d[N],u[N],c[N],row[N]; int s[N]; int m; int ans; bool flag; inline void remove(int ci){ int i,j; l[r[ci]] = l[ci]; r[l[ci]] = r[ci]; for (i = d[ci]; i != ci; 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]]--; } } } inline void resume(int ci){ int i,j; l[r[ci]] = r[l[ci]] = ci; for (i = u[ci]; i != ci; i = u[i]){ for (j = l[i]; j != i; j = l[j]){ u[d[j]] = j; d[u[j]] = j; s[c[j]]++; } } } void dfs(int k){ int i,j; if (k >= ans) return; if (r[head] == head){ ans = min(ans,k); flag = true; return ; } int MIN = inf, ci = 0; for (i = r[head]; i != head; i = r[i]){ if (s[i] < MIN){ MIN = s[i]; ci = i; } } remove(ci); for (i = d[ci]; i != ci; i = d[i]){ for (j = r[i]; j != i; j = r[j]){ remove(c[j]); } dfs(k + 1); for (j = l[i]; j != i; j = l[j]){ resume(c[j]); } } resume(ci); } inline void init(int m){ int i; for (i = 1; i <= m; ++i){ l[i] = i - 1; r[i] = i + 1; u[i] = d[i] = i; c[i] = i; s[i] = 0; } l[head] = m; r[head] = 1; r[m] = head; } int Get(){ int num = 0; char ch = getchar(); while (ch < '0' || ch > '9') ch = getchar(); while (ch >= '0' && ch <= '9'){ num = num*10 + ch - '0'; ch = getchar(); } return num; } int main(){ //freopen("data.in","r",stdin); int i,j; int tn,tm,p; int T; scanf("%d",&T); while (T--){ //scanf("%d%d%d",&tn,&tm,&p); tn = Get(); tm = Get(); p = Get(); int m = tn*tm; init(m); int size = m + 1; int x1,y1,x2,y2; for (int b = 0; b < p; ++b){ //scanf("%d%d%d%d",&x1,&y1,&x2,&y2); x1 = Get(); y1 = Get(); x2 = Get(); y2 = Get(); int rh = -1; x2--; y1++; for (i = x1; i <= x2; ++i){ for (j = y1; j <= y2; ++j){ int x = i*tm + j; row[size] = b + 1; c[size] = x; s[x]++; u[size] = u[x]; d[u[x]] = size; u[x] = size; d[size] = x; if (rh == -1){ l[size] = r[size] = size; rh = size; } else{ l[size] = l[rh]; r[l[rh]] = size; l[rh] = size; r[size] = rh; } size++; } } } ans = inf; flag = false; for (i = 1; i <= m; ++i){ if (s[i] == 0){ flag = true; break; } } if (flag){ printf("-1\n"); continue; } dfs(0); if (flag) printf("%d\n",ans); else printf("-1\n"); } return 0; }