西电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


没有AC不了的题,只有不努力的ACMER!
原文地址:https://www.cnblogs.com/--560/p/4506685.html