POJ 1185 炮兵布阵 状压DP

链接:http://poj.org/problem?id=1185

题意:一个地图上有两种地形,H和P,P上可以放一个炮,攻击范围是上下左右各两格,问的是最多可以再地图上放多少个炮。行N <= 100,列M <= 10。

思路:因为上下左右各两格内不能放置炮,所以每一行的状态数从2^10减少到60种。状态转移方程为:dp[i][j][k]=max(dp[i-1][k][l]+bb[j])。dp[i][j][k]表示在第i行状态为j,在第i-1行状态为k的前i行一共放置的炮塔数。bb[j]表示状态k中整行的炮塔数。手敲这道题后对状压DP开始有所熟悉。

代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<map>
#include<cstdlib>
#include<queue>
#include<stack>
#include<vector>
#include<ctype.h>
#include<algorithm>
#include<string>
#define PI acos(-1.0)
#define maxn 10005
#define INF 0x7fffffff
typedef long long ll;
using namespace std;
int judge(int x)
{
    if((x&(x<<1))==0&&((x&(x<<2))==0)&&(((x<<1)&(x<<2))==0))
        return 1;
    return 0;
}
int main()
{
    int row[105]={0};
    int aa[105]={0};
    int bb[105]={0};
    int top=0;
    char land[105][15];
    int dp[105][60][60]={0};
    int r,c;
    scanf("%d%d",&r,&c);
    for(int i=0;i<(1<<c);i++)
    {
        if(judge(i))
        {
            int k=i;
            while(k)
            {
                if(k%2==1)
                    bb[top]++;
                k/=2;
            }
            aa[top++]=i;
        }
    }
    for(int i=0;i<r;i++)
    {
        scanf("%s",land[i]);
        for(int j=0;j<c;j++)
        {
            row[i]*=2;
            if(land[i][j]=='P')
                row[i]++;
        }
    }
    for(int i=0;i<top;i++)
    {
        if((aa[i]&row[0])==aa[i])
        {
            dp[0][i][0]=bb[i];
        }
    }
    for(int i=0;i<top;i++)
    {
        for(int j=0;j<top;j++)
        {
            if((aa[i]&aa[j])==0&&(aa[i]&row[1])==aa[i]&&(aa[j]&row[0])==aa[j])
                dp[1][i][j]=dp[0][j][0]+bb[i];
        }
    }
    for(int i=2;i<r;i++)
    {
        for(int j=0;j<top;j++)
        {
            for(int k=0;k<top;k++)
            {
                for(int l=0;l<top;l++)
                {
                    if((aa[j]&aa[k])==0&&(aa[l]&aa[j])==0&&(aa[l]&aa[k])==0&&(aa[j]&row[i])==aa[j]&&(aa[k]&row[i-1])==aa[k]&&(aa[l]&row[i-2])==aa[l])
                    dp[i][j][k]=max(dp[i][j][k],dp[i-1][k][l]+bb[j]);
                }
            }

        }
    }
    int ans=0;
    for(int i=0;i<top;i++)
    {
        for(int j=0;j<top;j++)
        {
            if(dp[r-1][i][j]>ans)
                ans=dp[r-1][i][j];
        }
    }
    printf("%d\n",ans);
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值