POJ 1185 炮兵布阵 (动态规划)

题目链接:

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

AC代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define legal(a,b) a&b

int row,col;  //行列
int nums;  //仅是两个炮兵不互相攻击的条件下,符合条件的状态个数
int base[150];  //第i行的原地图压缩成的一个状态
int state[70]; //仅是两个炮兵不互相攻击的条件下,符合条件的状态(一个十进制数)
int soldier[70]; //对应着,在state[i]状态下能放多少个士兵
int dp[150][70][70];//dp[i][j][k] 表示第i行状态为state[j],第i-1行状态为state[k]时的最优解
char g[150][20];

void init()
{
    memset(base,0,sizeof(base));
    memset(state,0,sizeof(state));
    memset(soldier,0,sizeof(soldier));
    memset(dp,0,sizeof(dp));
}

int main()
{
    while(~scanf("%d %d", &row, &col))
    {
        init();
        nums = 0;
        for(int i = 0; i < row; i++)
        {
            scanf("%s", &g[i]);
            for(int j = 0; j < col; j++)
            {
                if(g[i][j] == 'H')
                {
                    base[i] += 1 << j;
                }
            }
        }
        for(int i = 0; i < (1 << col); i++)
        {
            if(legal(i, i << 1) || legal(i, i << 2))continue;
            int k = i;
            while(k)
            {
                soldier[nums] += k&1;
                k = k >> 1;
            }
            state[nums++] = i;
        }//nums为每一行首先满足士兵之间不相互攻击的状态数
        for(int i = 0; i < nums; i++) //先初始化dp[0][i][0],即初始化第1行的情况
        {
            if(legal(state[i],base[0])) continue;//第一行有士兵放到山上了,除去
            dp[0][i][0]=soldier[i];
        }
        for(int i = 0; i < nums; i++)
        {
            if(legal(state[i],base[1])) continue;//第二行有士兵放到山上了,除去
            for(int j = 0; j < nums; j++)
            {
                if(legal(state[j],base[0]))continue;//第一行有士兵放到山上了,除去
                if(legal(state[j],state[i]))continue;//第一行和第二行互相攻击了,除去
                dp[1][i][j]=max(dp[1][i][j] , dp[0][j][0]+soldier[i]);//状态转移方程,取第一行放士兵和第二行放士兵的士兵数最大值
            }
        }
        for(int r = 2; r < row; r++)//开始dp
        {
            for(int i = 0; i < nums; i++)
            {
                if(legal(state[i],base[r]))continue;//第r行有士兵放山上了,除去
                for(int j = 0; j < nums; j++)
                {
                    if(legal(state[j],base[r-1])) continue;//第r-1行士兵放山上了,除去
                    if(legal(state[i],state[j])) continue;//第r行和第r-1行士兵打架了
                    for(int k=0; k<nums; k++) //枚举第r-2行的状态
                    {
                        if(legal(state[k],base[r-2])) continue;
                        //第r-2行士兵放山上了,除去
                        if(legal(state[j],state[k])) continue;
                        //第r-1行的士兵和第r-2行的士兵相互攻击
                        if(legal(state[i],state[k])) continue;
                        //第r行的士兵和第r-2行士兵互相攻击了
                        dp[r][i][j]=max(dp[r][i][j] , dp[r-1][j][k]+soldier[i]);
                    }
                }
            }
        }
        int ans = 0;
        for(int i=0; i<nums; i++)
            for(int j=0; j<nums; j++) //枚举dp[row-1][i][j]
                ans=max(ans,dp[row-1][i][j]);
        printf("%d\n",ans);
    }
    return 0;
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值