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
Solution
感覺和上一題有點像
三維的狀壓DP,用了滾動數組
f[i][j][k] i表示所在行 j表示當前行狀態 k表示前一行狀態
預處理出一行中不會造成互相攻擊的狀態和每個狀態所含的1(炮兵部隊)
#include<iostream>
#include<cstring>
#include<cstdio>
#include<string>
#define Max(a,b) (a>b?a:b)
using namespace std;
int n,m,f[2][1050][1050],map[100],state[1050],num[1050],cnt;
int count(int x)
{
int y=0;
while(x)
{
if(x&1)y++;
x>>=1;
}
return y;
}
void init()
{
memset(map,0,sizeof(map));
memset(f,0,sizeof(f));
cnt=0;
for(int i=0;i<=(1<<m);i++)
{
bool b=0;
if(i&(i<<1))b=1;
if(i&(i<<2))b=1;
if(!b)
{
state[++cnt]=i;
num[cnt]=count(i);
}
}
}
int main()
{
while(~scanf("%d%d",&n,&m))
{
init();
for(int i=1;i<=n;i++)
{
char c[15];
cin>>c;
for(int j=0;j<m;j++)
{
map[i]<<=1;
if(c[j]=='P')map[i]+=1;
}
}
int ans=0,cur=0;
for(int i=1;i<=n;i++)
{
cur^=1;
for(int j=1;j<=cnt;j++)
{
if((state[j]&map[i])!=state[j])continue;
if(i==1)
{
f[cur][j][1]=num[j];
ans=Max(ans,f[cur][j][1]);
}
else
for(int k=1;k<=cnt;k++)
{
if(state[k]&state[j])continue;
if(i==2)
{
f[cur][j][k]=Max(f[cur][j][k],f[cur^1][k][1]+num[j]);
ans=Max(ans,f[cur][j][k]);
}
else
for(int l=1;l<=cnt;l++)
{
if(state[l]&state[k])continue;
if(state[l]&state[j])continue;
f[cur][j][k]=Max(f[cur^1][k][l]+num[j],f[cur][j][k]);
ans=Max(ans,f[cur][j][k]);
}
}
}
}
printf("%d\n",ans);
}
return 0;
}