poj1185 炮兵阵地

/*
状态压缩+位运算
假设山地:1,空地:0,空地放兵:1,那么每一行就是一个01串,可以用二进制了
首先,枚举每一行合法的放炮方法,就是不会打到彼此,与操作只有在两个数都是1的情况下为真
假设状态为i,(i<<1)&i相当于比较i的相邻两位,不打到彼此的话(i<<1)&i==0,就是没有相邻的两个1
所以合法的状态为(i<<1)&i==0 && (i<<2)&i==0
把这些合法的状态保存在state[]里面
原地图压缩在ori[]里面,合法状态还有满足炮不放在山上,那么只要ori里1所在的那个位置对应state里没有1
就可以了,即state[i]&base[i]=0
ps:选出来的state里山地对应的位置是0
i行,i-1行,i-2行两两不能攻击对方,类似的
state[i]&state[i-1]=0 state[i]&state[i-2]=0 state[i-1]&state[i-2]=0

dp[r][i][j]表示第r行状态为state[i],r-1行为state[j]的最大值
dp[r][i][j]=max(dp[r][i][j],dp[r-1][j][k]+soldier[i])
*/
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
#define maxr 110
#define maxc 15
#define maxn 70
#define mem(a) memset(a,0,sizeof(a))
#define check(a,b) (a)&(b) //判断合法
int row,col;
int sum;//合法状态数
int ori[maxn];
int state[maxn];
int soldier[maxn];//state[i]状态下放的士兵数
int dp[maxn][maxn][maxn];
char g[maxr][maxc];

int main()
{
    mem(ori);
    mem(state);
    mem(soldier);
    mem(dp);
    sum=0;

    scanf("%d%d",&row,&col);
    for(int i=0;i<row;i++)
    {
        scanf("%s",g[i]);
        for(int j=0;j<col;j++)
            if(g[i][j]=='H')
                ori[i]+=(1<<j);
    }

    for(int i=0;i<(1<<col);i++)
    {
        if(check(i,i<<1) || check(i,i<<2))//冲突
            continue;
        int k=i;
        //计算k状态下的1
        while(k)
        {
            soldier[sum]+=(k&1);
            k=k>>1;
        }
        state[sum++]=i;
    }

    //初始化第一行状态
    for(int i=0;i<sum;i++)
    {
        if(check(state[i],ori[0])) continue;
        dp[0][i][0]=soldier[i];
    }

    //初始化第二行状态
    for(int i=0;i<sum;i++)
    {
        if(check(state[i],ori[1])) continue;
        for(int j=0;j<sum;j++)
        {
            if(check(state[j],ori[0])) continue;
            if(check(state[i],state[j])) continue;
            dp[1][i][j]=max(dp[1][i][j],dp[0][j][0]+soldier[i]);
        }
    }

    //从第3行开始直到最后
    for(int r=2;r<row;r++)
    {
        for(int i=0;i<sum;i++)//第r行状态
        {
            if(check(state[i],ori[r])) continue;
            for(int j=0;j<sum;j++)//第r-1行状态
            {
                if(check(state[j],ori[r-1])) continue;
                if(check(state[i],state[j])) continue;

                for(int k=0;k<sum;k++)//第r-2行状态
                {
                    if(check(state[k],ori[r-2])) continue;
                    if(check(state[k],state[j])) continue;
                    if(check(state[k],state[i])) continue;

                    dp[r][i][j]=max(dp[r][i][j],dp[r-1][j][k]+soldier[i]);
                }
            }
        }
    }

    int ans=0;
    for(int i=0;i<sum;i++)
        for(int j=0;j<sum;j++)
            ans=max(ans,dp[row-1][i][j]);
    printf("%d\n",ans);
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值