zoukankan      html  css  js  c++  java
  • zoj

    题意:一个 n x m 的矩形(1 <= n, m <= 30),现给出这个矩形中 p 个(1 <= p <= 500)子矩形的左下角与右下角坐标,问最少用多少个子矩形能够恰好组成这个 n x m 的大矩形。 

    题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=3372

    ——>>这是精确覆盖问题,而DLX正是解决精确覆盖问题的有利武器。。

          模型转换:将原矩形变成一行,作为 DLX 中的列,表示要被覆盖一次且仅一次的目标。子矩形则是行中的一些点,每一个子矩形作为 DLX 的一行,它所覆盖行中的点的位置标为1,其余位标为0,则问题转化为:选出最少的行,使得选出的行中每一列有且仅有一个1,这正是 DLX 解决的问题。。

          注:在往下一层 dfs 的时候,假设检測返回值为真,可别来个return true,这时会中断后面的搜索(非常隐秘地 WA 了几发敲打)。。为了方便,我不要返回值了。。

          为了加快搜索,能够来个剪枝,dfs 时检測当前深度是否 >= 已搜索到的可满足要求的长度。。

    #include <cstdio>
    #include <cstring>
    
    const int MAXN = 30 + 10;
    const int MAXR = 500 + 10;
    const int MAXC = 30 * 30 + 10;
    const int MAXNODE = MAXR * MAXC;
    const int INF = 0x3f3f3f3f;
    
    struct DLX
    {
        int sz;
        int H[MAXR], S[MAXC];
        int row[MAXNODE], col[MAXNODE];
        int U[MAXNODE], D[MAXNODE], L[MAXNODE], R[MAXNODE];
        int Min;
    
        void Init(int n)
        {
            for (int i = 0; i <= n; ++i)
            {
                U[i] = D[i] = i;
                L[i] = i - 1;
                R[i] = i + 1;
            }
            L[0] = n;
            R[n] = 0;
    
            sz = n + 1;
            memset(S, 0, sizeof(S));
            memset(H, -1, sizeof(H));
        }
    
        void Link(const int& r, const int& c)
        {
            row[sz] = r;
            col[sz] = c;
            D[sz] = D[c];
            U[D[c]] = sz;
            D[c] = sz;
            U[sz] = c;
            if (H[r] == -1)
            {
                H[r] = L[sz] = R[sz] = sz;
            }
            else
            {
                R[sz] = R[H[r]];
                L[R[H[r]]] = sz;
                R[H[r]] = sz;
                L[sz] = H[r];
            }
            S[c]++;
            sz++;
        }
    
        void Remove(const int& c)
        {
            L[R[c]] = L[c];
            R[L[c]] = R[c];
            for (int i = D[c]; i != c; i = D[i])
            {
                for (int j = R[i]; j != i; j = R[j])
                {
                    U[D[j]] = U[j];
                    D[U[j]] = D[j];
                    S[col[j]]--;
                }
            }
        }
    
        void Restore(const int& c)
        {
            for (int i = U[c]; i != c; i = U[i])
            {
                for (int j = L[i]; j != i; j = L[j])
                {
                    S[col[j]]++;
                    U[D[j]] = j;
                    D[U[j]] = j;
                }
            }
            L[R[c]] = c;
            R[L[c]] = c;
        }
    
        void Dfs(int cur)
        {
            if (cur >= Min) return;
    
            if (R[0] == 0)
            {
                if (cur < Min)
                {
                    Min = cur;
                }
                return;
            }
    
            int c = R[0];
            for (int i = R[0]; i != 0; i = R[i])
            {
                if (S[i] < S[c])
                {
                    c = i;
                }
            }
    
            Remove(c);
            for (int i = D[c]; i != c; i = D[i])
            {
                for (int j = R[i]; j != i; j = R[j])
                {
                    Remove(col[j]);
                }
                Dfs(cur + 1);
                for (int j = L[i]; j != i; j = L[j])
                {
                    Restore(col[j]);
                }
            }
            Restore(c);
        }
    
        void Solve()
        {
            Min = INF;
            Dfs(0);
            Min != INF ? printf("%d
    ", Min) : puts("-1");
        }
    
    } dlx;
    
    int ReadInt()
    {
        int ret = 0;
        char ch;
    
        while ((ch = getchar()) && ch >= '0' && ch <= '9')
        {
            ret = ret * 10 + ch - '0';
        }
    
        return ret;
    }
    
    void Read()
    {
        int n, m, p;
        scanf("%d%d%d", &n, &m, &p);
        dlx.Init(n * m);
        getchar();
        for (int i = 1; i <= p; ++i)
        {
            int x1 = ReadInt();
            int y1 = ReadInt();
            int x2 = ReadInt();
            int y2 = ReadInt();
            for (int j = y1 + 1; j <= y2; ++j)
            {
                for (int k = x1 + 1; k <= x2; ++k)
                {
                    dlx.Link(i, (j - 1) * n + k);
                }
            }
        }
    }
    
    int main()
    {
        int T;
        scanf("%d", &T);
    
        while (T--)
        {
            Read();
            dlx.Solve();
        }
    
        return 0;
    }
    
    


  • 相关阅读:
    二分搜索
    Shell 字符串处理、获取文件名和后缀名
    sqlldr使用说明
    Linux cached过高问题
    算法时间复杂度
    #if,#ifdef,#ifndef的区别
    memcpy momove strcmp源码实现
    怎么解决/bin/sh: arm-linux-gcc: not found make
    性能文章
    linux
  • 原文地址:https://www.cnblogs.com/zfyouxi/p/4271644.html
Copyright © 2011-2022 走看看