西电oj 1038 状压dp

西电oj 1038  状压dp

1038: 裁玻璃

时间限制: 1 Sec  内存限制: 128 MB
提交: 33  解决: 4
[提交][状态][讨论版]

题目描述

张老板的玻璃店开张了,生意火爆。今天,隔壁玻璃店的刘老板拿来一块玻璃,意在刁难张老板。刘老板说:“我这块玻璃是由N(行)*M(列)小正方形玻璃拼成的,但是其中有一些玻璃坏了,我希望你现在把它裁成尽量多的2*2的小玻璃,而且这些小玻璃都不能有坏的地方。如果你裁出来的块数不是最多的,我就把你赶出建材市场。”
现在,张老板来拜托你帮他解决这个问题,聪明的你可以告诉张老板,最多能裁出多少块2*2的小玻璃吗?

输入

有多组输入数据,第一行为一个数字T,代表有T组输入数据 (0<T<=30)。
接下来为T组数据,每组数据的第一行为两个正整数N和M(1<=N<=10,1<=M<=10),表示玻璃的大小,接下来的N行、每行M个数字(0或1)表示玻璃中每个位置的状态,0表示这个位置是坏的,1表示这个位置是好的。

输出

一共T行。
对于每组数据,输出一个整数,表示最多的2*2小玻璃块数。

样例输入

2

2 3

1 1 1

1 1 1

4 4

0 0 1 1

0 1 1 1

1 1 1 1

1 1 1 1

样例输出

1

3
思路:和poj1185一样,状压dp,dp(i,j)=max(dp(i,j),dp(i-1,k)+sum[j])(状态j,k存在合法且不冲突)
    dp表示第i行的状态为j时的玻璃数,按行进行递推,sum[j]表示状态为j时这一行的玻璃数。

#include<iostream>

#include<cstdio>

#include<cstring>

#include<cstdlib>

#include<algorithm>



using namespace std;



const int maxn=1100;

const int INF=(1<<29);



int N,M;

int Map[maxn];

int dp[maxn][maxn];

int state[maxn],sum[maxn],cnt;



void InitState()

{

    memset(state,0,sizeof(state));

    cnt=0;

    for(int i=0;i<(1<<(M-1));i++){

        if((i&(i<<1))) continue;

        state[cnt++]=i;

    }

}



void InitSum()

{

    memset(sum,0,sizeof(sum));

    for(int i=0;i<cnt;i++){

        for(int j=0;j<M-1;j++){

            if(state[i]&(1<<j)) sum[i]++;

        }

    }

}



bool jud_map(int i,int row)

{

    int s=state[i];

    bool flag=1;

    for(int j=0;j<M-1;j++){

        if(s&(1<<j)){

            if(Map[row]&(1<<j)&&(Map[row]&(1<<(j+1)))&&(Map[row+1]&(1<<j))&&(Map[row+1]&(1<<(j+1)))) continue;

            else{

                flag=0;break;

            }

        }

    }

    return flag;

}



bool jud(int a,int b)

{

    int s=state[a],t=state[b];

    if((s&t)||(s&(t<<1))||((s<<1)&t)) return 0;

    return 1;

}



int main()

{

    int T;cin>>T;

    while(T--){

        cin>>N>>M;

        memset(Map,0,sizeof(Map));

        for(int i=1;i<=N;i++){

            int t;

            for(int j=0;j<M;j++){

                scanf("%d",&t);

                if(t) Map[i]|=(1<<j);

            }

        }

        InitState();

        InitSum();

        memset(dp,0,sizeof(dp));

        for(int i=1;i<=N-1;i++){

            for(int j=0;j<cnt;j++){

                if(!jud_map(j,i)) continue;

                if(i==1){

                    dp[i][j]=max(dp[i][j],sum[j]);

                    continue;

                }

                else{

                    for(int k=0;k<cnt;k++){

                        if((!jud_map(k,i-1))||(!jud(j,k))) continue;

                        dp[i][j]=max(dp[i][j],dp[i-1][k]+sum[j]);

                    }

                }

            }

        }

        int ans=0;

        for(int i=0;i<cnt;i++){

            if(dp[N-1][i]>ans) ans=dp[N-1][i];

        }

        cout<<ans<<endl;

    }

    return 0;

}
View Code

 



你可能感兴趣的:(dp)