HDU 2640

题目



#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;

int t,n,m,dp[2][13][13],num,ok[13],cnt[13];
char map[105][10];

/*
    状态是每个物体的第三行...
    由于第二行的特殊性,加上不能重叠,可以知道第三行状态很少一共有:
    00000000 , 01001000
    01000000 , 01000100
    00100000 , 01000010
    00010000 , 00100100
    00001000 , 00100010
    00000100 , 00010010
    00000010
    13种.
*/
inline void init(){//求出合法状态
    ok[0]=cnt[0]=0;
    num=1;
    for(int i=1;i+1<m;i++){
        ok[num]=(1<<i),cnt[num]=1,num++;
        for(int j=i+3;j+1<m;j++){
            ok[num]=(1<<i)+(1<<j),cnt[num]=2,num++;
        }
    }
}

inline bool suit(int st,int i){//第i行状态为st,可以吗?需要考虑三行
    for(int j=0;j<m;j++){
        if(st&(1<<j)){
            if(map[i][j]=='#' || map[i-1][j]=='#' || map[i-1][j-1]=='#' || map[i-1][j+1]=='#' || map[i-2][j]=='#')
                return 0;
        }
    }
    return 1;
}

inline bool Can1(int st1,int st2){//对于物体,第三行的状态和第二行的状态合法不
    int a[3][8];
    memset(a,0,sizeof(a));
    for(int i=0;i<8;i++){
        if(st1&(1<<i)){
            a[0][i]++,a[1][i]++,a[1][i-1]++,a[1][i+1]++,a[2][i]++;
        }
        if(st2&(1<<i)){
            a[1][i]++,a[2][i]++,a[2][i-1]++,a[2][i+1]++;
        }
    }
    for(int i=0;i<8;i++){
        if(a[0][i]>1 || a[1][i]>1 || a[2][i]>1) return 0;
    }
    return 1;
}

inline bool Can2(int st1,int st2){//对于物体,第三行的状态和第一行的状态合法不
    for(int i=0;i<m;i++){
        if(st1&(1<<i)){
            if(st2&(1<<i)){
                return 0;
            }
        }
    }
    return 1;
}
int main(){
    scanf("%d",&t);
    while(t--){
        scanf("%d%d",&n,&m);
        for(int i=0;i<n;i++) scanf("%s",map[i]);
        if(n<=2 || m<=2 ) puts("0");
        else{
            init();
            int now=0;
            memset(dp[now],0,sizeof(dp[now]));
            for(int i=2;i<n;i++){
                now^=1;
                memset(dp[now],0,sizeof(dp[now]));
                for(int j=0;j<num;j++){
                    int st1=ok[j];
                    for(int k=0;k<num;k++){
                        int st2=ok[k];
                        for(int r=0;r<num;r++){
                            int st3=ok[r];
                            if(!suit(st3,i)) continue;
                            if(!Can1(st3,st1)) continue;
                            if(!Can2(st3,st2)) continue;
                            dp[now][r][j]=max(dp[now][r][j],dp[1-now][j][k]+cnt[r]);
                        }
                    }
                }
            }
            int ans=0;
            for(int i=0;i<num;i++)
                for(int j=0;j<num;j++)
                    ans=max(ans,dp[now][i][j]);
            printf("%d\n",ans);
        }
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值