POJ 1185 炮兵布陣

2021-09-25 18:36:53 字數 2485 閱讀 9810

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

如果在地圖中的灰色所標識的平原上部署一支炮兵部隊,則圖中的黑色的網格表示它能夠攻擊到的區域:沿橫向左右各兩格,沿縱向上下各兩格。圖上其它白色網格均攻擊不到。從圖上可見炮兵的攻擊範圍不受地形的影響。 

現在,將軍們規劃如何部署炮兵部隊,在防止誤傷的前提下(保證任何兩支炮兵部隊之間不能互相攻擊,即任何一支炮兵部隊都不在其他支炮兵部隊的攻擊範圍內),在整個地圖區域內最多能夠擺放多少我軍的炮兵部隊。 

第一行包含兩個由空格分割開的正整數,分別表示n和m; 

接下來的n行,每一行含有連續的m個字元('p'或者'h'),中間沒有空格。按順序表示地圖中每一行的資料。n <= 100;m <= 10。

僅一行,包含乙個整數k,表示最多能擺放的炮兵部隊的數量。

5 4

phpp

pphh

pppp

phpp

phhp

6
經典的狀壓dp題目,因為每行的長度不超過10,而且每個位置只有放置士兵和不放置士兵兩種操作,自然而然地想到用二進位制來表示每一行的士兵放置情況了,也就是說,我們將一行壓縮成乙個用數字表示的狀態,數字在二進位制下某個位置的數代表某個位置士兵的放置情況。

然後呢,說一下這個題,由圖中我們發現,同乙個士兵的攻擊範圍是上下左右各兩個位置,那麼在同一行中,不可以布置有相鄰和隔著乙個位置的士兵,我們記這一行的狀態為 x ,如果 x & (x <<1 ) != 0 || x & (x<<2) != 0 ,x<<1可以看作將所有士兵的位置向左移動乙個位置,因此,如果 x & (x <<1 ) != 0則說明狀態x存在兩個相鄰的士兵,因此這個狀態是不合法的,x << 2 就同理了。

我們注意到,除了第一行不會受到前兩行狀態的影響(前兩行沒有士兵),以及第二行只會受到第一行的影響外,其餘每一行的狀態,也就是士兵的布置情況,都會受到前兩行的狀態影響,因此我們在布置第 r(r >=2)行的士兵的時候,需要判斷r-1,r-2行的狀態是否和第r行的狀態起衝突,我們記這三行的狀態分別為 x,y,z,對應 r,r-1,r-2行,如果 x & y || x & z || y & z ,顯然,此時這三行會其衝突,只要這三行的狀態不滿足上式,此時第r行的狀態才可以由前一行轉移而來。

總結一下這類題目的一些套路,類似於這個題一樣的,如poj-2411,這類題目的特點都是某一行的狀態影響下面x行的狀態,那麼我們需要預處理出前x行的狀態,因為前x行的狀態並不是完全受前x行的影響,而x+1行及之後都將受到前x行狀態的影響,因此對於x + 1行及以後,判斷某狀態是否合法需要往上列舉x行,,而我們往往根據x的大小決定dp陣列的維度,一般情況下,第一維度表示當前所在行,第二維度表示上一行的狀態,第三維度表示上上行的狀態.....這樣一來我們就可以很方便的判斷轉移條件了。

#include#include#include#include#include#include#include#include#include#include#define bug cout << "**********" << endl

using namespace std;

typedef long long ll;

const int inf = 0x3f3f3f3f;

const int mod = 1e8;

const int max = 1e2 + 10;

int n, m, tot;

int dp[110][max][max]; //dp[i][j][k]中,i代表行數,j代表當前行的狀態,k代表上一行的狀態

int base[max]; //記錄原始地圖狀態

int state[max]; //記錄同一行中不互相功擊的合法狀態

int soldier[max]; //記錄和state[i]狀態下對應的布置士兵數量

int main()

}} tot = 0;

for (int i = 0;i < (1 << m); i++) //列舉不互相功擊情況下的合法狀態

state[tot++] = i; //儲存合法狀態

} for (int i = 0;i < tot; i++) //預處理第一行

for (int i = 0; i < tot; i++) //預處理第二行

}for (int r = 2;r < n; r++) //開始處理第三行及之後}}

} int ans = 0; //記錄最大士兵布置數

for (int i = 0; i < tot; i++)

}printf("%d\n", ans);

} return 0;

}

POJ 1185 炮兵布陣

解題思路 原來不會寫,只能想到去暴搜,真的沒有想到是個狀壓dp題目。還是覺得挺難的,找了好幾份題解才明白的。include include include include using namespace std const int maxn 120 int n,m n行m列 int cnt 僅僅滿足...

POJ 1185 炮兵布陣 (動態規劃)

include include include include using namespace std define legal a,b a b int row,col 行列 int nums 僅是兩個炮兵不互相攻擊的條件下,符合條件的狀態個數 int base 150 第i行的原地圖壓縮成的乙個狀...

poj 1185 炮兵布陣 狀壓dp

炮兵陣地 time limit 2000ms memory limit 65536k total submissions 29250 accepted 11331 description 司令部的將軍們打算在n m的網格地圖上部署他們的炮兵部隊。乙個n m的地圖由n行m列組成,地圖的每一格可能是山地...