炮兵阵地-状态压缩型动态规划

炮兵阵地

Description

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

如果在地图中的灰色所标识的平原上部署一支炮兵部队,则图中的黑色的网格表示它能够攻击到的区域:沿横向左右各两格,沿纵向上下各两格。图上其它白色网格均攻击不到。从图上可见炮兵的攻击范围不受地形的影响。 
现在,将军们规划如何部署炮兵部队,在防止误伤的前提下(保证任何两支炮兵部队之间不能互相攻击,即任何一支炮兵部队都不在其他支炮兵部队的攻击范围内),在整个地图区域内最多能够摆放多少我军的炮兵部队。 

Input

第一行包含两个由空格分割开的正整数,分别表示N和M; 
接下来的N行,每一行含有连续的M个字符('P'或者'H'),中间没有空格。按顺序表示地图中每一行的数据。N <= 100;M <= 10。

Output

仅一行,包含一个整数K,表示最多能摆放的炮兵部队的数量。

Sample Input

5 4
PHPP
PPHH
PPPP
PHPP
PHHP

Sample Output

6

做的第一题状态压缩型动态规划,先将列数m转化为可行的状态,例如样例中4可以有 2^4个状态态,其中符合题意的只有

0,1,2,4,8,9,转化为2进制数:0000,0001,0010,0100,1000,1001共6种状态

再将地形也转化为二进制数P=0,H=1,第一行就是1011

在求第一行和第二行的dp状态方程的时候要单独初始化

第一行的时候 可以用state[i]&mp[0]可以快速判段此状态和地形会不会冲突

第二行的时候要枚举第一行状态

第三行到第n行只要暴力枚举前两行的状态就可以了

详细

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
char mmp[105][12];
int mp[105];
int state[100];
int num[100];
int dp[105][100][100];                  //第一个代表行数 第二个代表i-1的状态 第三个代表i-2的状态
int main()
{
    int n,m;
    scanf("%d%d",&n,&m);
    for(int i=0; i<n; i++)scanf("%s",mmp[i]);
    for(int i=0; i<n; i++)
    {
        for(int j=0; j<m; j++)
        {
            if(mmp[i][j]=='H')
                mp[i]=mp[i]*2+1;
            else
                mp[i]=mp[i]*2;
        }
    }
    int ans = 0;                              //计数有几个符合的状态
    for(int i=0; i<(1<<m); i++)
    {
        if((i&(i<<1))||(i&(i<<2)))continue;
        int temp=i;
        while(temp)
        {
            num[ans]=num[ans]+(temp&1); //num[ans]=num[ans]+temp&1;这样写是错误的,运算符优先级,被坑死了
            temp>>=1;
        }
        state[ans++]=i;
        printf("%d\n",i);
    }
    for(int i=0; i<ans; i++)                  //初始化第一行
    {
        if(mp[0]&state[i])continue;

        dp[0][i][0]=num[i];
    }
    for(int i=0; i<ans; i++)
    {
        if(state[i]&mp[1])continue;
        for(int j=0; j<ans; j++)
        {
            if(state[j]&mp[0])continue;
            if(state[i]&state[j])continue;
            dp[1][i][j]=max(dp[1][i][j],dp[0][j][0]+num[i]);
        }
    }
    for(int i=2; i<=n; i++)                   //2到n行
        for(int j=0; j<ans; j++)             //枚举i-1行的状态
        {
            if(state[j]&mp[i-1])continue;
            for(int k=0; k<ans; k++)         //枚举i-2行的状态
            {
                if(state[k]&mp[i-2])continue;
                for(int now=0; now<ans; now++)  //枚举当前第i行的状态
                {
                    if(mp[i]&state[now])continue;     //枚举的第i行的状态和地形没有冲突
                    if(state[j]&state[k])continue;    //枚举的i-1行和i-2行没有冲突
                    if(state[j]&state[now])continue;  //枚举的第i行的状态i-1行没有冲突
                    if(state[k]&state[now])continue;  //枚举的第i行的状态i-2行没有冲突
                    dp[i][now][j]=max(dp[i-1][j][k]+num[now],dp[i][now][j]);
                }
            }
        }
    int Max=0;
    for(int i=0; i<ans; i++)
        for(int j=0; j<ans; j++)
            Max=max(dp[n-1][i][j],Max);
    printf("%d\n",Max);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_37804064/article/details/79587725