POJ-1185-炮兵阵地(状压DP)

炮兵阵地

司令部的将军们打算在NM的网格地图上部署他们的炮兵部队。一个NM的地图由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

解题思路:

题意:一个地图有H,P两种点,P可以放炮兵,每个炮兵可以攻击上下左右相邻两格的地方。问最多可以放多少个炮兵而不互相攻击。
几乎是裸DP了呀,需要注意的就是炮兵可以攻击到两层。那么在按层数往下DP的时候需要知道上一层和上上一层的状态是什么,因此需要增加一维。保存上一层的状态。dp[i][j][k]表示第i层,mark[j]状态下,上一层是mark[k]状态下能放炮兵的最大值。
由于交了几次都超时了。也不知道是哪个地方,就改了一堆可以优化时间的地方。

AC代码:

//#include<bits/stdc++.h>
#include <iostream>
#include <cstdio>
#include <cstring>
#include <math.h>
#include <algorithm>
#include <map>
#include <queue>
#include <deque>
#define ios std::ios::sync_with_stdio(false)
#define int long long
using namespace std;
const int N = 100;
int cnt = 0;	// 记录状态数
int mark[61];	// 状态最多60种,开大了还超内存
int dp[102][61][61];	
int a[102];	   // 整数记录每行的地图,优化时间
int value[61]; // 保存每个状态下炮兵的个数,每个状态只计算一次,优化时间
int n,m,en;	   // en用来确定右边界,只计算一次(1<<m) 优化时间

bool check(int lev,int sta)
{
    if((sta&a[lev]) != 0)
        return false;
    return true;
}

int count_(int x)
{
    int res = 0;
    while(x)
    {
        res ++;
        x -= (x&(-x)); // lowbit优化时间
    }
    return res;
}

signed  main()
{
    for(int i = 0 ; i < (1<<10) ; i ++)
        if(((i>>1)&i) == 0 && ((i>>2)&i) == 0)
        {
            value[cnt]  = count_(i);
            mark[cnt++] = i;
        }
    mark[cnt] = (1<<12); // 设定一个最大的右边界,不然会出现死循环
    cin>>n>>m;    en = (1<<m);
    for(int i = 0 ; i < n ; i ++)
    {
        int tmp = 0;
        for(int j = 0 ; j < m ; j ++)
        {
            char buf;  cin>>buf;
            if(buf == 'H')  tmp += (1<<(m-1-j));
        }
        a[i] = tmp;
    }
    memset(dp,0,sizeof(dp));
    for(int i = 0 ; mark[i] < en ; i ++) // 先处理第一层的情况
    {
        bool flag = check(0,mark[i]);
        int  val = value[i];
        for(int j = 0 ; mark[j] < en ; j ++)
        {
            if(flag && (mark[i]&mark[j]) == 0)
                dp[0][i][j] = val;
            else
                dp[0][i][j] = 0;
        }
    }
    for(int i = 1; i < n ; i ++)  // 枚举层数
    {
        for(int j = 0 ; mark[j] < en ; j ++) // 枚举当前层状态
        {
           if(!check(i,mark[j])) continue;
           int val = value[j];
           for(int k = 0 ; mark[k] < en ; k ++) // 枚举上一层状态
           {
               if((mark[j]&mark[k]) != 0) continue;
               for(int l = 0 ; mark[l] < en ; l ++) // 枚举上上层状态
               {
                    if((mark[j]&mark[l]) != 0 || (mark[k]&mark[l]) != 0) continue;
                    dp[i][j][k] = max(dp[i][j][k],dp[i-1][k][l]+val);
               }
           }
        }
    }
    int ans = 0;
    for(int j = 0 ; mark[j] < en ; j ++) 
        for(int k = 0 ; mark[k] < en ; k ++)
            ans = max(dp[n-1][j][k],ans);
    cout<<ans<<endl;
    return 0;
}
/** 
代码超时的话可以试试这组数据
100 10
PHPPPHPPPP
PPHHPPHHHH
PPPPPPPPPP
PHPPPHPPPP
PHHPPHHPHP
PHPPPHPPPP
PPHHPPHHHH
PPPPPPPPPP
PHPPPHPPPP
PHHPPHHPHP
PHPPPHPPPP
PPHHPPHHHH
PPPPPPPPPP
PHPPPHPPPP
PHHPPHHPHP
PHPPPHPPPP
PPHHPPHHHH
PPPPPPPPPP
PHPPPHPPPP
PHHPPHHPHP
PHPPPHPPPP
PPHHPPHHHH
PPPPPPPPPP
PHPPPHPPPP
PHHPPHHPHP
PHPPPHPPPP
PPHHPPHHHH
PPPPPPPPPP
PHPPPHPPPP
PHHPPHHPHP
PHPPPHPPPP
PPHHPPHHHH
PPPPPPPPPP
PHPPPHPPPP
PHHPPHHPHP
PHPPPHPPPP
PPHHPPHHHH
PPPPPPPPPP
PHPPPHPPPP
PHHPPHHPHP
PHPPPHPPPP
PPHHPPHHHH
PPPPPPPPPP
PHPPPHPPPP
PHHPPHHPHP
PHPPPHPPPP
PPHHPPHHHH
PPPPPPPPPP
PHPPPHPPPP
PHHPPHHPHP
PHPPPHPPPP
PPHHPPHHHH
PPPPPPPPPP
PHPPPHPPPP
PHHPPHHPHP
PHPPPHPPPP
PPHHPPHHHH
PPPPPPPPPP
PHPPPHPPPP
PHHPPHHPHP
PHPPPHPPPP
PPHHPPHHHH
PPPPPPPPPP
PHPPPHPPPP
PHHPPHHPHP
PHPPPHPPPP
PPHHPPHHHH
PPPPPPPPPP
PHPPPHPPPP
PHHPPHHPHP
PHPPPHPPPP
PPHHPPHHHH
PPPPPPPPPP
PHPPPHPPPP
PHHPPHHPHP
PHPPPHPPPP
PPHHPPHHHH
PPPPPPPPPP
PHPPPHPPPP
PHHPPHHPHP
PHPPPHPPPP
PPHHPPHHHH
PPPPPPPPPP
PHPPPHPPPP
PHHPPHHPHP
PHPPPHPPPP
PPHHPPHHHH
PPPPPPPPPP
PHPPPHPPPP
PHHPPHHPHP
PHPPPHPPPP
PPHHPPHHHH
PPPPPPPPPP
PHPPPHPPPP
PHHPPHHPHP
PHPPPHPPPP
PPHHPPHHHH
PPPPPPPPPP
PHPPPHPPPP
PHHPPHHPHP
**/

发布了104 篇原创文章 · 获赞 7 · 访问量 4064

猜你喜欢

转载自blog.csdn.net/qq_43461168/article/details/104189562