zoukankan      html  css  js  c++  java
  • poj2032Square Carpets(IDA* + dancing links)

    题目请戳这里

    题目大意:给一个H行W列的01矩阵,求最少用多少个正方形框住所有的1.

    题目分析:又是一个红果果的重复覆盖模型.DLX搞之!

    枚举矩阵所有的子正方形,全1的话建图.判断全1的时候,用了一个递推,dp[i][j][w][h]表示左上角(i,j)的位置开始长h宽w的矩形中1的个数,这样后面可以迅速判断某个正方形是否全1.

    不过此题直接搜一直TLE,然后改成迭代加深就比较愉快啦得意

    详情请见代码:

    #include <iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    
    const int N = 11;
    const int M = 50005;
    int dp[N][N][N][N];
    int n,m,num,ans;
    int mp[N][N];
    bool vis[105];
    int s[M],h[M],col[M],u[M],d[M],l[M],r[M];
    
    void init()
    {
        memset(h,0,sizeof(h));
        memset(s,0,sizeof(s));
        int i,c;
        c = m * n;
        for(i = 0;i <= c;i ++)
        {
            u[i] = d[i] = i;
            l[i] = (i + c)%(c + 1);
            r[i] = (i + 1)%(c + 1);
        }
        num = c + 1;
    }
    
    void ins(int i,int j)
    {
        if(h[i])
        {
            r[num] = h[i];
            l[num] = l[h[i]];
            r[l[num]] = l[r[num]] = num;
        }
        else
            h[i] = l[num] = r[num] = num;
        s[j] ++;
        u[num] = u[j];
        d[num] = j;
        d[u[num]] = num;
        u[j] = num;
        col[num] = j;
        num ++;
    }
    void del(int c)
    {
        for(int i = u[c];i != c;i = u[i])
            l[r[i]] = l[i],r[l[i]] = r[i];
    }
    void resume(int c)
    {
        for(int i = d[c];i != c;i = d[i])
            l[r[i]] = r[l[i]] = i;
    }
    
    int A()
    {
        int i,j,k,ret;
        ret = 0;
        memset(vis,false,sizeof(vis));
        for(i = r[0];i;i = r[i])
        {
            if(vis[i] == false)
            {
                ret ++;
                vis[i] = true;
                for(j = d[i];j != i;j = d[j])
                    for(k = r[j];k != j;k = r[k])
                        vis[col[k]] = true;
            }
        }
        return ret;
    }
    
    bool dfs(int k,int lim)
    {
        if(k + A() > lim)
            return false;
        if(!r[0])
        {
    //        ans = min(ans,k);
            return true;
        }
        int i,j,c,mn = M;
        for(i = r[0];i;i = r[i])
        {
            if(s[i] < mn)
            {
                mn = s[i];
                c = i;
            }
        }
        for(i = d[c];i != c;i = d[i])
        {
            del(i);
            for(j = l[i];j != i;j = l[j])
                del(j);
            if(dfs(k + 1,lim)) return true;
            for(j = r[i];j != i;j = r[j])
                resume(j);
            resume(i);
        }
        return false;
    }
    
    bool canfuck(int x,int y,int z)
    {
        return dp[x][y][z][z] == z * z;
        int i,j;
        for(i = x;i <= x + z - 1;i ++)
            for(j = y;j <= y + z - 1;j ++)
                if(mp[i][j] == 0)
                    return false;
        return true;
    }
    
    void fuckba(int x,int y,int z,int id)
    {
        int i,j;
        for(i = x;i <= x + z - 1;i ++)
            for(j = y;j <= y + z - 1;j ++)
                ins(id,(i - 1) * m + j);
    }
    void build()
    {
        int i,j,k;
        memset(dp,0,sizeof(dp));
        for(i = 1;i <= n;i ++)
            for(j = 1;j <= m;j ++)
                scanf("%d",&mp[i][j]),dp[i][j][1][1] = mp[i][j];
        for(int ii = 1;ii <= n;ii ++)
            for(int jj = 1;jj <= m;jj ++)
            {
                for(i = 1;i + ii <= n + 1;i ++)
                {
                    for(j = 1;j + jj <= 1 + m;j ++)
                    {
                        dp[i][j][ii][jj] = dp[i][j][ii - 1][jj - 1] + dp[i + ii - 1][j][1][jj - 1] + dp[i][j + jj - 1][ii - 1][1] + dp[i + ii - 1][j + jj - 1][1][1];
                    }
                }
            }
        init();
        int rownum = 1;
        for(k = 1;k <= min(n,m);k ++)//枚举边长
        {
            for(i = 1;i <= n - k + 1;i ++)
            {
                for(j = 1;j <= m - k + 1;j ++)
                {
                    if(canfuck(i,j,k))
                        fuckba(i,j,k,rownum);
                    rownum ++;
                }
            }
        }
        for(i = 1;i <= n * m;i ++)
            if(s[i] == 0)
                l[r[i]] = l[i],r[l[i]] = r[i];
    }
    void fuck()
    {
    //    ans = M;TLE....
    //    dfs(0);
    //    printf("%d
    ",ans);
        ans = 0;
        while(!dfs(0,ans ++));
        printf("%d
    ",ans - 1);
    }
    int main()
    {
        while(scanf("%d%d",&m,&n),(m + n))
        {
            build();
            fuck();
        }
        return 0;
    }


  • 相关阅读:
    根据输入的个数,打印每行做多输出3个的for循环
    在启动页面后面再加载一个广告页,可以定制动画等
    frame.size.height无法直接赋值问题
    iOS开发远程推送
    iOS——UIKeyboardWillShowNotification 监听键盘高度变化
    iOS 浅谈本地通知 UILocalNotification
    iOS中assign、copy 、retain等关键字的含义
    GCD
    xocde快速定位崩溃代码
    关于xcode打包app
  • 原文地址:https://www.cnblogs.com/riasky/p/3481865.html
Copyright © 2011-2022 走看看