zoukankan      html  css  js  c++  java
  • 邻面合并(merging)

    邻面合并(merging)

    题目描述

     

    给定一个N×MN×M的网格,每个格子上写有0或1。现在用一些长方形覆盖其中写有1的格子,长方形的每条边都要与坐标轴平行。要求:每个写着1的格子都要被覆盖,长方形不可以重叠(重复绘制也多少会增加性能开销),也不能覆盖到任何一个写着0的格子(不然绘制结果就不正确了)。请问最少需要多少长方形?

     

    输入

     

    输入文件第一行两个正整数N,MN,M,表示网格大小为NN行MM列。

    接下来的NN行,每行MM个正整数AijAij(保证均为0或1),其中第ii行jj列的正整数表示网格ii行jj列里填的数。

     

    输出

     

    输出文件包含一行一个正整数,表示最少需要的长方形数量。

     

    样例输入

    <span style="color:#333333"><span style="color:#333333">4 4
    1 1 1 0
    1 1 1 1
    0 0 1 1
    0 0 1 1</span></span>

    样例输出

    <span style="color:#333333"><span style="color:#333333">3</span></span>

    提示

     

    样例解释

    一种行的覆盖方案(粗线表示分割线):

     

    数据范围

    对于30% 的数据:N,M≤5N,M≤5。

    对于100% 的数据:N≤100,M≤8N≤100,M≤8。

     

    来源


    solution

    状压dp,我想不到

    令f[i][S]表示前i行,状态为S

    状态为1表示是一个新的开始

    比如状态10010

    表示划成了2个矩形,开头在1 4

    转移时枚举是否能接起来

    #include<cstdio>
    #include<iostream>
    #include<cstdlib>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #define inf 1e9
    using namespace std;
    int n,m,s[105][10],f[102][1<<9];
    int num=0;
    bool pd(int k,int S){
        for(int i=0;i<m;i++){
            int t=(1<<i);
            if((S&t)&&s[k][i]==0)return 0;
        }
        int fl=0;
        for(int i=0;i<m;i++){
            int t=(1<<i);
            if(S&t)fl=1;
            if(s[k][i]==1&&!fl)return 0;
            if(s[k][i]==0)fl=0;
        }
        return 1;
    }
    int cost(int k,int S,int T){
        int sum=0;
        for(int i=0;i<m;i++){
            int t=(1<<i);
            if(S&t)sum++;
        }
         
        for(int i=0;i<m;i++){
            int t=(1<<i);
            if((S&t)&&(T&t)){
                int ed=i;for(;s[k][ed]&&ed<=m;ed++)if(ed!=i&&(S&(1<<ed)))break;
                //cout<<"ed "<<ed<<' '<<i<<endl;
                bool fl=0;
                for(int j=i+1;j<ed;j++)if(T&(1<<j)){fl=1;break;}
                for(int j=i+1;j<ed;j++)if(!s[k-1][j]){fl=1;break;}
                if(!fl&&((T&(1<<ed))||!s[k-1][ed]))sum--;
            }
        }
        return sum;
    }
    int main()
    {
        cin>>n>>m;
        for(int i=1;i<=n;i++){
            for(int j=0;j<m;j++){
                scanf("%d",&s[i][j]);
            }
             
        }
        for(int i=0;i<=n;i++)
        for(int j=0;j<(1<<m);j++)f[i][j]=inf;
        f[0][0]=0;
        for(int i=1;i<=n;i++){
            for(int S=0;S<(1<<m);S++){
                if(pd(i,S)){
                for(int T=0;T<(1<<m);T++){
                    if(f[i-1][T]!=inf){
                        //cout<<i<<' '<<S<<' '<<T<<endl;
                         
                        f[i][S]=min(f[i][S],f[i-1][T]+cost(i,S,T));
                        //cout<<cost(i,S,T)<<endl;
                        //system("pause");
                    }
                }
                }
            }
        }
        int ans=inf;
        for(int S=0;S<(1<<m);S++)ans=min(ans,f[n][S]);
        cout<<ans<<endl;
        return 0;
    }
  • 相关阅读:
    简单到一步安装 xgboost (Windows 64位环境)——anaconda环境
    python中的字符数字之间的转换函数
    Python之基础练习题
    SAS基础语句
    linux 查询目录大小并排序
    loadrunner get、Post 请求的一个java vuser 脚本
    mysql 解析 json格式的字段
    java 使用fast json 与 Map List互相转换
    windows 系统 端口数调整 比避免出现 time_wait连接状态过多
    java 枚举 enum使用
  • 原文地址:https://www.cnblogs.com/liankewei/p/10358799.html
Copyright © 2011-2022 走看看