邻面合并(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;
}

 

posted @ 2018-10-26 19:57  liankewei123456  阅读(428)  评论(0编辑  收藏  举报