[NOI2001]炮兵陣地
阿新 • • 發佈:2018-11-11
題目描述
司令部的將軍們打算在NM的網格地圖上部署他們的炮兵部隊。一個NM的地圖由N行M列組成,地圖的每一格可能是山地(用“H” 表示),也可能是平原(用“P”表示),如下圖。在每一格平原地形上最多可以佈置一支炮兵部隊(山地上不能夠部署炮兵部隊);一支炮兵部隊在地圖上的攻擊範圍如圖中黑色區域所示:
如果在地圖中的灰色所標識的平原上部署一支炮兵部隊,則圖中的黑色的網格表示它能夠攻擊到的區域:沿橫向左右各兩格,沿縱向上下各兩格。圖上其它白色網格均攻擊不到。從圖上可見炮兵的攻擊範圍不受地形的影響。 現在,將軍們規劃如何部署炮兵部隊,在防止誤傷的前提下(保證任何兩支炮兵部隊之間不能互相攻擊,即任何一支炮兵部隊都不在其他支炮兵部隊的攻擊範圍內),在整個地圖區域內最多能夠擺放多少我軍的炮兵部隊。
輸入輸出格式
輸入格式:
第一行包含兩個由空格分割開的正整數,分別表示N和M;
接下來的N行,每一行含有連續的M個字元(‘P’或者‘H’),中間沒有空格。按順序表示地圖中每一行的資料。N≤100;M≤10。
輸出格式:
僅一行,包含一個整數K,表示最多能擺放的炮兵部隊的數量。
輸入輸出樣例
輸入樣例#1:
5 4
PHPP
PPHH
PPPP
PHPP
PHHP
輸出樣例#1:
6
狀壓dp
由於\(M\leq 10\)而且相鄰3個位置內不能放兩個以上炮兵,所以其實真正每行能放的狀態是很少的。
其實每一次對新的一行轉移時對他有影響的只有向上兩行,加到狀態裡就行了。
那麼先找出每一種可行的狀態,兩兩看是否匹配。
暴力轉移即可
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #define LL long long #define max(a,b) ((a)>(b)? (a):(b)) #define min(a,b) ((a)<(b)? (a):(b)) using namespace std; int b[101],i,m,n,j,k,a[101][101][101],d[100],v[100],bl[101][101],l,ans,bb[101][101][101]; char c; int main() { scanf("%d%d",&n,&m); for(i=1;i<=n;i++) for(j=1;j<=m;j++) { b[i]<<=1; scanf("%c",&c); while(c!='P' && c!='H') scanf("%c",&c); if(c=='H') b[i]+=1; } for(i=0;i<=(1<<m)-1;i++) { if((i&(i<<1))||(i&(i<<2))) continue; int t=i; k=0; while(t) t-=t & -t, k+=1; v[++v[0]]=k; d[++d[0]]=i; } for(i=1;i<=d[0];i++) if(!(b[1]&d[i])) { bb[1][1][i]=1; a[1][1][i]=v[i]; } for(i=1;i<=d[0];i++) for(j=1;j<=d[0];j++) if(!(d[i]&d[j])) bl[i][j]=1; for(i=2;i<=n;i++) for(j=1;j<=d[0];j++) for(l=1;l<=d[0];l++) if(bb[i-1][j][l]) for(k=1;k<=d[0];k++) if(bl[k][l] && bl[k][j] &&(!(d[k]&b[i]))) { bb[i][l][k]=1; a[i][l][k]=max(a[i][l][k],a[i-1][j][l]+v[k]); if(i==n) ans=max(ans,a[i][l][k]); } printf("%d",ans); }