题目描述
司令部的将军们打算在NM的网格地图上部署他们的炮兵部队。一个NM的地图由N行M列组成,地图的每一格可能是山地(用”H” 表示),也可能是平原(用”P”表示),如下图。在每一格平原地形上最多可以布置一支炮兵部队(山地上不能够部署炮兵部队);一支炮兵部队在地图上的攻击范围如图中黑色区域所示:
![](https://wx1.sinaimg.cn/mw690/006bDeXUgy1fwh92f9zxej307n04wmxe.jpg)
如果在地图中的灰色所标识的平原上部署一支炮兵部队,则图中的黑色的网格表示它能够攻击到的区域:沿横向左右各两格,沿纵向上下各两格。图上其它白色网格均攻击不到。从图上可见炮兵的攻击范围不受地形的影响。
现在,将军们规划如何部署炮兵部队,在防止误伤的前提下(保证任何两支炮兵部队之间不能互相攻击,即任何一支炮兵部队都不在其他支炮兵部队的攻击范围内),在整个地图区域内最多能够摆放多少我军的炮兵部队。
输入
第一行包含两个由空格分割开的正整数,分别表示N和M;
接下来的N行,每一行含有连续的M个字符(‘P’或者’H’),中间没有空格。按顺序表示地图中每一行的数据。N <= 100;M <= 10。
输出
仅一行,包含一个整数K,表示最多能摆放的炮兵部队的数量。
样例
- Input
5 4
PHPP
PPHH
PPPP
PHPP
PHHP - Output
6
题解
- 跟前面的玉米地类似,但是这道题不仅要跟上一行进行比较,还要跟上上行进行比较。
- 我们用数组sta来存放所有不会产生横向冲突的状态,用数组num来存放每个状态所对应的炮兵数,用dp[i][stai][pre]表示第i行中第stai个状态、i-1行pre状态下的炮兵最大数,用dp[i-1][pre][prepre]表示i-1行pre状态、i-2行prepre状态下的炮兵最大数,中间需要判断stai、pre、以及prepre三种状态之间是否相互冲突。状态转移方程为:
dp[i][stai][pre]=max(dp[i][stai][pre],dp[i-1][pre][prepre]+num[stai])
Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
| #include<bits/stdc++.h> using namespace std; #define LL long long int #define INIT(a,b) memset(a,b,sizeof(a)) const int INF=0x3f3f3f3f; const int Mod=1e9+7; const int MaxN=1e7+5; const int MAX=0x7fffffff; const int MIN=-0x7fffffff; int cant[1000]; int sta[100],num[105]; int N,M,All=0; int dp[105][105][105]; int main() { cin>>N>>M; char x; for(int i=1;i<=N;i++){ for(int j=1;j<=M;j++){ cin>>x; if(x=='H') cant[i]+=(1<<(M-j)); } } for(int i=0;i<(1<<M);i++){ if((i&(i<<1))||(i&(i<<2)))continue; int k=i; while(k){ num[All]+=(k&1); k=k>>1; } sta[All++]=i; }
for(int i=0;i<All;i++){ if(sta[i]&cant[1])continue; dp[1][i][1]=num[i]; } for(int i=0;i<All;i++){ if(sta[i]&cant[2])continue; for(int j=0;j<All;j++){ if(sta[j]&cant[1])continue; if(sta[j]&sta[i])continue; dp[2][i][j]=max(dp[2][i][j],dp[1][j][1]+num[i]); } } for(int i=3;i<=N;i++){ for(int stai=0;stai<All;stai++){ if(sta[stai]&cant[i])continue; for(int pre=0;pre<All;pre++){ if(sta[pre]&cant[i-1])continue; if(sta[pre]&sta[stai])continue; for(int prepre=0;prepre<All;prepre++){ if(sta[prepre]&cant[i-2])continue; if(sta[prepre]&sta[stai])continue; if(sta[prepre]&sta[pre])continue; dp[i][stai][pre]=max(dp[i-1][pre][prepre]+num[stai],dp[i][stai][pre]); } } } } int ans=0; for(int i=0;i<All;i++) for(int j=0;j<All;j++) ans=max(ans,dp[N][i][j]); cout<<ans<<endl; return 0; }
|