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

 

posted @ 2012-10-30 17:18  E_star  阅读(286)  评论(0编辑  收藏  举报