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

 

posted @ 2012-10-29 18:42  E_star  阅读(304)  评论(0编辑  收藏  举报