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;

}

 

你可能感兴趣的:(覆盖)