炮兵阵地(POJ1185)

博客提到状态压缩dp问题,强调要先列举好表示压缩状态的数,不然状态数过多,会导致数组存不下,出现空间大小不足的情况。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

状态压缩dp,该题需要先列举好表示压缩状态的数,否则状态数太多,数组存不下,空间大小不足,,,

#include<iostream>
#include<algorithm>
#include<fstream>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<string>
#include<cmath>
#include<cctype>
#include<vector>
#include<limits.h>
#include<queue>


using namespace std;

int row,col;    //行和列
int base[110];  //第i行地图压缩成的状态
int state[70];  //一行中2个炮兵不互相攻击时符合的状态数
int soldier[70];    //对应state状态时的士兵数
int dp[110][70][70];    //400或者70都行
//dp[i][j][k] 表示第i行状态为state[j],第i-1行状态为state[k]
char g[110][15];

int main()
{
    int i,j,ans,_j,k,r,nums;
    scanf("%d%d",&row,&col);
    for(i=1; i<=row; ++i)   //平地为0,高地为1
    {
        scanf("%s",g[i]);
        for(j=col-1,_j=1; j>=0; _j<<=1,--j) //计算原始地图的状态数
        {
            if(g[i][j]=='H')
                base[i]+=_j;
        }
    }
    for(i=0,nums=1; i<(1<<col); ++i)    //计算2个炮兵之间不互相攻击时的所有状态
    {
        if(i&(i<<1)||i&(i<<2))
            continue;           //出现了2个士兵之间相互攻击
        k=i;
        while(k)
        {
            soldier[nums]+=k&1; //等价于k%2,判断k的二进制数里有几个1
            k>>=1;
        }
        state[nums++]=i;    //保存合法状态
    }   //1表示有炮兵,2表示没有炮兵
    for(i=1; i<nums; ++i)   //初始化第1行的情况
    {
        if(state[i]&base[1])    //炮兵不能在山上
            continue;
        dp[1][i][0]=soldier[i];
    }
    for(i=1; i<nums; ++i)   //初始化第3行
    {
        if(state[i]&base[2])
            continue;
        for(j=1; j<nums; ++j)   //枚举第1行的情况
        {
            if((state[j]&base[1])||(state[i]&state[j]))
                continue;
            dp[2][i][j]=max(dp[2][i][j],dp[1][j][0]+soldier[i]);

        }
    }
    for(r=3; r<=row; ++r)   //从第3行开始dp到最后
    {
        for(i=1; i<nums; ++i)   //枚举第r行的状态
        {
            if(state[i]&base[r])
                continue;
            for(j=1; j<nums; ++j)   //枚举第r-1行的状态
            {
                if((state[j]&base[r-1])||(state[i]&state[j]))
                    continue;
                for(k=1; k<nums; ++k)   //枚举第r-2行的状态
                {
                    if((state[k]&base[r-2])||(state[i]&state[k])||(state[j]&state[k]))
                        continue;
                    dp[r][i][j]=max(dp[r][i][j],dp[r-1][j][k]+soldier[i]);
                }
            }
        }
    }
    //    for(i=0,ans=0; i<nums; i++)
//            for(j=0; j<nums; j++) //枚举dp[row-1][i][j]
//                ans=max(ans,dp[row-1][i][j]);
    ans=*max_element(&dp[0][0][0],&dp[row][nums][nums]);
    printf("%d\n",ans);
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值