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;
}