題面
題目描述
司令部的將軍們打算在NM的網格地圖上部署他們的炮兵部隊。一個NM的地圖由N行M列組成,地圖的每一格可能是山地(用”H” 表示),也可能是平原(用”P”表示),如下圖。在每一格平原地形上最多可以佈置一支炮兵部隊(山地上不能夠部署炮兵部隊);一支炮兵部隊在地圖上的攻擊範圍如圖中黑色區域所示:
輸入格式
第一行包含兩個由空格分割開的正整數,分別表示N和M;
接下來的N行,每一行含有連續的M個字符(‘P’或者’H’),中間沒有空格。按順序表示地圖中每一行的數據。N <= 100;M <= 10。
輸出格式
僅一行,包含一個整數K,表示最多能擺放的炮兵部隊的數量。
題解
很明顯,一個炮兵部隊的擺放受到前兩行的制約。
狀態:
代表第i行狀態是j,第i-1行狀態是k的答案。
我們令 是二進制數i的1的個數。
代表狀態j是否能在第i行出現。
所以狀態轉移方程:
如果 ,那麼有
## code
#include<bits/stdc++.h>
using namespace std;
inline int read(){
int num=0;
char c=' ';
bool flag=true;
for(;c>'9'||c<'0';c=getchar())
if(c=='-')
flag=false;
for(;c>='0'&&c<='9';num=num*10+c-48,c=getchar());
return flag ? num : -num;
}
const int maxn=200;
int n,m,dp[maxn][maxn][maxn];
int a[maxn];
int top,s[maxn],num[maxn];
void init(){
n=read();m=read();
int k=1<<m;
for(int i=0;i<k;i++)
if((i&(i<<1))==0&&(i&(i<<2))==0){
s[top]=i;
num[top]=0;
int j=i;
while(j)
{
num[top]+=j%2;
j/=2;
}
top++;
}
string s;
for(int i=0;i<n;i++){
a[i]=0;
cin>>s;
for(int j=0;j<m;j++)
if (s[j]=='P')
a[i]+=1<<j;
}
}
void one_and_two(){//前兩行的dp值需要預先處理,否則無法轉移。
for(int j=0;j<top;j++)
{
if((s[j]&a[0])!=s[j])
continue;
for(int k=0;k<top;k++)
dp[0][j][k]=num[j];
}
if(n>1)
for(int j=0;j<top;j++)
{
if((s[j]&a[1])!=s[j])
continue;
for(int k=0;k<top;k++)
{
if((s[j]&s[k])==0)
dp[1][j][k]=dp[0][k][0]+num[j];
}
}
}
void work(){
for (int i=2;i<n;i++)
{
for(int j=0;j<top;j++)
{
if((s[j]&a[i])!=s[j])
continue;
for(int k=0;k<top;k++)
{
if(s[j]&s[k])
continue;
for(int h=0;h<top;h++)
{
if (s[j]&s[h])
continue;
dp[i][j][k]=max(dp[i][j][k],dp[i-1][k][h]);
}
dp[i][j][k]+=num[j];
}
}
}
int ans=0;
for(int j=0;j<top;j++)
{
for(int k=0;k<top;k++)
ans=max(ans,dp[n-1][j][k]);
}
printf("%d\n",ans);
}
int main(){
init();
one_and_two();
work();
return 0;
}