洛谷P2704 [NOI2001]炮兵陣地 [狀壓DP]
阿新 • • 發佈:2018-07-21
ref font radi 空格 一行 包含 tar syn clas
題目傳送門
炮兵陣地
題目描述
司令部的將軍們打算在N*M的網格地圖上部署他們的炮兵部隊。一個N*M的地圖由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模板,但是反正考場上沒想到。。。
只要枚舉本行的所有情況和上面兩行的所有情況,然後判斷一下在轉移即可。
Code:
//It is made by HolseLee on 21th July 2018 //Luogu.org P2704 #include<bits/stdc++.h> using namespace std; int n,m,ans,a[105],dp[(1<<10)][(1<<10)][3],sum[(1<<10)]; inline int get(int x) { int ret=0; while(x){if(x&1)ret++;x>>=1;} return ret; } int main() { freopen("cannon.in","r",stdin); freopen("cannon.out","w",stdout); ios::sync_with_stdio(false); cin>>n>>m; char op; for(int i=0;i<n;i++) for(int j=0;j<m;j++){ cin>>op;a[i]<<=1; a[i]+=(op==‘H‘?1:0);} for(int S=0;S<(1<<m);S++) sum[S]=get(S); for(int S=0;S<(1<<m);S++) if(!((S&a[0])||(S&(S<<1))||(S&(S<<2)))) dp[0][S][0]=sum[S]; for(int L=0;L<(1<<m);L++) for(int S=0;S<(1<<m);S++) if(!((L&S)||(L&a[0])||(S&a[1])||(L&(L<<1))||(L&(L<<2))||(S&(S<<1))||(S&(S<<2)))) dp[L][S][1]=sum[L]+sum[S]; for(int i=2;i<n;i++) for(int L=0;L<(1<<m);L++){ if((L&a[i-1])||(L&(L<<1))||(L&(L<<2)))continue; for(int S=0;S<(1<<m);S++){ if((S&L)||(S&a[i])||(S&(S<<1))||(S&(S<<2)))continue; for(int FL=0;FL<(1<<m);FL++){ if((FL&L)||(FL&S)||(FL&a[i-2])||(FL&(FL<<1))||(FL&(FL<<2)))continue; dp[L][S][i%3]=max(dp[L][S][i%3],dp[FL][L][(i-1)%3]+sum[S]); } } } for(int L=0;L<(1<<m);L++) for(int S=0;S<(1<<m);S++) ans=max(ans,dp[L][S][(n-1)%3]); cout<<ans<<"\n"; return 0; }
洛谷P2704 [NOI2001]炮兵陣地 [狀壓DP]