司令部的將軍們打算在\(N * M\)的網格地圖上部署他們的炮兵部隊。一個\(N * M\)的地圖由N行M列組成,地圖的每一格多是山地(用\(「H」\) 表示),也多是平原(用\(「P」\)表示),以下圖。在每一格平原地形上最多能夠佈置一支炮兵部隊(山地上不可以部署炮兵部隊);一支炮兵部隊在地圖上的攻擊範圍如圖中黑色區域所示:
若是在地圖中的灰色所標識的平原上部署一支炮兵部隊,則圖中的黑色的網格表示它可以攻擊到的區域:沿橫向左右各兩格,沿縱向上下各兩格。圖上其它白色網格均攻擊不到。從圖上可見炮兵的攻擊範圍不受地形的影響。 如今,將軍們規劃如何部署炮兵部隊,在防止誤傷的前提下(保證任何兩支炮兵部隊之間不能互相攻擊,即任何一支炮兵部隊都不在其餘支炮兵部隊的攻擊範圍內),在整個地圖區域內最多可以擺放多少我軍的炮兵部隊。數組
第一行包含兩個由空格分割開的正整數,分別表示\(N\)和\(M\);spa
接下來的\(N\)行,每一行含有連續的\(M\)個字符(\(‘P’\)或者\(‘H’\)),中間沒有空格。按順序表示地圖中每一行的數據。\(N≤100;M≤10\)。3d
僅一行,包含一個整數\(K\),表示最多能擺放的炮兵部隊的數量。code
5 4
PHPP
PPHH
PPPP
PHPP
PHHPblog
6部署
\(狀壓DP\)get
\(dfs\)求出狀態和狀態數string
設\(N[i][j]\)表示第i行第j個狀態所用的炮兵數量io
設一個轉移狀態\(dp[i][j][k]\)是當前的炮兵數class
\(i\)表示第\(i\)行,\(j\)表示第\(i\)行第\(j\)個狀態,\(k\)表示第\(i-1\)行第\(k\)個狀態
方程也特別簡單
\(dp[i][j][k] = max(dp[i][j][k], dp[i-1][k][l] + N[i][j]);\)
而後枚舉出第\(n\)行的全部狀態和第\(n-1\)行的全部狀態,取一個\(max\)
可是會遇到一個問題,就是數組會開的很大,這時經過\(dfs\)發現
當全都是\(P\)時,也只有\(60\)種狀態,因此能夠減少數組.
#include <cstdio> #include <cstring> #define re register inline int read() { int s = 0, f = ' '; char ch = getchar(); while(ch < '0' || ch > '9') { if(ch == '-') f = '-'; ch = getchar();} while(ch >= '0' && ch <= '9') s = (s << 3) + (s << 1) + ch - '0', ch = getchar(); return f == '-' ? -s : s; } inline int max(int a, int b) { return a > b ? a : b;} const int Max = 12; const int MAX = 102; const int INF = 0x7fffffff; int n, m, dp[MAX][65][65]; int st[MAX][65], sum[MAX], N[MAX][65]; char ch[MAX][Max]; void dfs(int x, int Sum, int j, int p) { if(j > m) { st[x][++sum[x]] = Sum; N[x][sum[x]] = p; return ; } dfs(x, Sum, j + 1, p); if(ch[x][j] == 'P') dfs(x, Sum + (1 << j), j + 3, p + 1); } int main() { n = read(); m = read(); for(re int i = 1; i <= n; ++ i) scanf("%s", ch[i] + 1); for(re int i = 1; i <= n; ++ i) dfs(i,0,0,0); for(re int i = 1; i <= n; ++ i) for(re int j = 1; j <= sum[i]; ++ j) dp[i][j][0] = N[i][j]; for(re int i = 1; i <= sum[2]; ++ i) for(re int j = 1; j <= sum[1]; ++ j) { if(st[2][i] & st[1][j]) continue; dp[2][i][j] = max(dp[2][i][j], dp[1][j][0] + N[2][i]); } for(re int i = 3; i <= n; ++ i) for(re int j = 1; j <= sum[i]; ++ j) for(re int k = 1; k <= sum[i-1]; ++ k) for(re int l = 1; l <= sum[i-2]; ++ l) { if(st[i][j] & st[i-1][k]) continue; if(st[i][j] & st[i-2][l]) continue; if(st[i-1][k] & st[i-2][l]) continue; dp[i][j][k] = max(dp[i][j][k], dp[i-1][k][l] + N[i][j]); } int ans = -INF; for(re int i = 1; i <= sum[n]; ++ i) for(re int j = 1; j <= sum[n-1]; ++ j) ans = max(ans, dp[n][i][j]); printf("%d",ans); return 0; }