FZU Problem 1686 神龙的难题 DLX 重复覆盖
http://acm.fzu.edu.cn/problem.php?pid=1686
题意:
给定一个n*m的01矩阵,给出每次可以覆盖的行与列(相当于利用小矩形覆盖大矩形一样),求使用最少的次数(小矩形的个数)将所有的1都覆盖。
思路:
这里没有要求不能重复覆盖,所以属于重复覆盖的类型。只要把所有出现的1当作列,然后枚举每个可能的小矩形,枚举他所能覆盖的列,建立十字链标。然后套用DLX 重复覆盖模板即可。
吐槽一下:这里h()函数减枝时如果是> 就会tle >= 就AC 了。。。无语了,看来等于的结果很多啊。
心得:做了几个DLX的题目,感觉这类题目和网络流类似,只要能把模型想出来,建好图,套模板就好了。
View Code
#include <cstdio> #include <cstring> #include <iostream> #include <cmath> using namespace std; // freopen("data.in","r",stdin); #define CL(a,num) memset((a),(num),sizeof(a)) #define inf 0x7f7f7f7f #define M 16 #define N 150001 const int head = 0; int l[N],r[N],d[N],u[N],c[N]; int s[N]; bool hash[N]; int mat[M][M]; int num[M][M]; int n1,m1; int ans; void remove(int ci){ int i; for(i = d[ci]; i != ci; i = d[i]){ l[r[i]] = l[i]; r[l[i]] = r[i]; } } void resume(int ci){ int i; for(i = u[ci]; i != ci; i = u[i]){ l[r[i]] = i; r[l[i]] = i; } } int h(){ int i,j,k; int res = 0; CL(hash,false); for (i = r[head]; i != head; i = r[i]){ if (!hash[i]){ res++; hash[i] = true; for (j = d[i]; j != i; j = d[j]){ for (k = r[j]; k != j; k = r[k]){ hash[c[k]] = true; } } } } return res; } void dfs(int dep){ int i,j; if (dep + h() >= ans) return;//这里一定要有=否则汇tle if (r[head] == head){ ans = min(ans,dep); return ; } int MIN = inf , ci = 0; for (i = r[head]; i != head; i = r[i]){ if (s[i] < MIN){ MIN = s[i]; ci = i; } } for (i = d[ci]; i != ci; i = d[i]){ remove(i); for (j = r[i]; j != i; j = r[j]){ remove(j); } dfs(dep + 1); for (j = l[i]; j != i; j = l[j]){ resume(j); } resume(i); } return ; } void init(int i){ l[i] = i - 1; r[i] = i + 1; u[i] = d[i] = i; c[i] = i; s[i] = 0; } int main(){ //freopen("data.in","r",stdin); int i,j; while (~scanf("%d%d",&n1,&m1)){ int m = 0; int size = 0; CL(num,0); for (i = 1; i <= n1; ++i){ for (j = 1; j <= m1; ++j){ scanf("%d",&mat[i][j]); if (mat[i][j] == 1){ init(++m); num[i][j] = m; } } } // printf("%d\n",m); l[head] = m; r[head] = 1; r[m] = head; size = m + 1; int ni,mi,ki,kj; scanf("%d%d",&ni,&mi); for (i = 1; i <= n1 - ni + 1; ++i){ for (j = 1; j <= m1 - mi + 1; ++j){ int rh = -1; for (ki = i; ki < i + ni; ++ki){ for (kj = j; kj < j + mi; ++kj){ if (mat[ki][kj]){ int x = num[ki][kj]; 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; dfs(0); printf("%d\n",ans); } return 0; }