Poj 1185 炮兵阵地 状态压缩

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

题目大意:

在N*M的网格地图上部署炮兵部队。地图的每一格可能是山地(用"H" 表示),也可能是平原(用"P"表示),如下图。在每一格平原地形上最多可以布置一支炮兵部队(山地上不能够部署炮兵部队);一支炮兵部队在地图上的攻击范围如图中黑色区域所示: 


如果在地图中的灰色所标识的平原上部署一支炮兵部队,则图中的黑色的网格表示它能够攻击到的区域。炮兵的攻击范围不受地形的影响。 
现在,如何部署炮兵部队,使得任何一支炮兵部队都不在其他支炮兵部队的攻击范围内,在整个地图区域内最多能够摆放多少我军的炮兵部队。

解题思路:由于每行最多只有10个位置,故状态压缩 枚举每个状态即可,同时应该 注意的是  每行的状态是由上面一行和上面两行  的状态决定的。

另外,可以知道一个位置有炮兵,则左右两个空位置不能有炮兵,因此可以先把  有效状态提取出来,然后在判断这个状态的时候,再判断这个位置是否是山地。

代码如下:

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
int dp[105][70][70];  ///dp[i][j][k]:第i行为状态j,i-1行为状态k的最大放法
int sta[70];           ///合法状态数
int cot[70];           ///合法状态下本行能放的炮兵数
int map[1<<11];        ///存地图
int n,m;
int init()
{
    memset(dp,0,sizeof(dp));
    memset(sta,0,sizeof(sta));
    memset(map,0,sizeof(map));
    memset(cot,0,sizeof(cot));
}
void solve()
{
    int num=(1<<m);
    int ct=0;
    for(int i=0;i<=num;i++)  ///枚举合法状态
        if( (i&(i<<1))==0 && (i&(i<<2))==0 )///注意(i&(i<<1))==0不能写成(i&(i<<1)==0),(==优先级高于&)
        sta[ct++]=i;

    for(int i=0;i<ct;i++)    ///计算合法状态炮兵数
    {
        int cn=0;
        for(int j=0;j<=m;j++)
            if( sta[i]&(1<<j) ) cn++;
        cot[i]=cn;
        if( (map[1]|sta[i])==map[1] ) dp[1][i][0]=cn;  ///初始化第一行,零行为0
    }

    for(int i=2; i<=n; i++)
    {
        //if(map[i]==0) continue;
        for(int k1=0; k1<ct; k1++)
        {
            if((sta[k1]|map[i-1])!=map[i-1])  continue;
            for(int k2=0; k2<ct; k2++)
            {
                if( (sta[k2]|map[i-2])!=map[i-2] ) continue;
                if( (sta[k1]&sta[k2])!=0 ) continue;
                    for(int j=0; j<ct; j++)
                        if( (sta[j]|map[i])==map[i] && (sta[j]&sta[k1])==0  && (sta[j]&sta[k2])==0 )
                            dp[i][j][k1]=max(dp[i][j][k1],dp[i-1][k1][k2]+cot[j]);
            }
        }
    }
    int ans=0;
    for(int i=0;i<ct;i++)
        for(int j=0;j<ct;j++)
        ans=max(dp[n][i][j],ans);
    printf("%d\n",ans);
}
int main()
{
    //freopen("in.txt","r",stdin);
    int t;
    scanf("%d",&t);
    while(t--)
    {
        init();
        scanf("%d%d",&n,&m);
        if(m==0||n==0) {printf("0\n");continue;}
        char s[12];
        for(int i=1;i<=n;i++)
        {
            scanf("%s",s);
            for(int j=0;j<m;j++)
                if(s[j]=='P') map[i]=(map[i]<<1)+1;///从左往右1为P(平原),0为H(山地)
                else map[i]=(map[i]<<1)+0;
        }
        solve();
    }
    return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值