洛谷P2704 [NOI2001]炮兵陣地題解

題目描述

司令部的將軍們打算在\(N * M\)的網格地圖上部署他們的炮兵部隊。一個\(N * M\)的地圖由N行M列組成,地圖的每一格多是山地(用\(「H」\) 表示),也多是平原(用\(「P」\)表示),以下圖。在每一格平原地形上最多能夠佈置一支炮兵部隊(山地上不可以部署炮兵部隊);一支炮兵部隊在地圖上的攻擊範圍如圖中黑色區域所示:

若是在地圖中的灰色所標識的平原上部署一支炮兵部隊,則圖中的黑色的網格表示它可以攻擊到的區域:沿橫向左右各兩格,沿縱向上下各兩格。圖上其它白色網格均攻擊不到。從圖上可見炮兵的攻擊範圍不受地形的影響。 如今,將軍們規劃如何部署炮兵部隊,在防止誤傷的前提下(保證任何兩支炮兵部隊之間不能互相攻擊,即任何一支炮兵部隊都不在其餘支炮兵部隊的攻擊範圍內),在整個地圖區域內最多可以擺放多少我軍的炮兵部隊。數組

輸入格式

第一行包含兩個由空格分割開的正整數,分別表示\(N\)\(M\)spa

接下來的\(N\)行,每一行含有連續的\(M\)個字符(\(‘P’\)或者\(‘H’\)),中間沒有空格。按順序表示地圖中每一行的數據。\(N≤100;M≤10\)3d

輸出格式

僅一行,包含一個整數\(K\),表示最多能擺放的炮兵部隊的數量。code

輸入輸出樣例

輸入 #1

5 4
PHPP
PPHH
PPPP
PHPP
PHHPblog

輸出 #1

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;
}
相關文章
相關標籤/搜索