【cofun1368】炮兵陣地
Description
司令部的將軍們打算在NM的網格地圖上部署他們的炮兵部隊。一個NM的地圖由N行M列組成,地圖的每一格可能是山地(用“H” 表示),也可能是平原(用“P”表示),如下圖。在每一格平原地形上最多可以佈置一支炮兵部隊(山地上不能夠部署炮兵部隊);一支炮兵部隊在地圖上的攻擊範圍如圖中黑色區域所示:
如果在地圖中的灰色所標識的平原上部署一支炮兵部隊,則圖中的黑色的網格表示它能夠攻擊到的區域:沿橫向左右各兩格,沿縱向上下各兩格。圖上其它白色網格均攻擊不到。從圖上可見炮兵的攻擊範圍不受地形的影響。
現在,將軍們規劃如何部署炮兵部隊,在防止誤傷的前提下(保證任何兩支炮兵部隊之間不能互相攻擊,即任何一支炮兵部隊都不在其他支炮兵部隊的攻擊範圍內),在整個地圖區域內最多能夠擺放多少我軍的炮兵部隊。
Input Format
文件的第一行包含兩個由空格分割開的正整數,分別表示N和M; 接下來的N行,每一行含有連續的M個字符(‘P’或者‘H’),中間沒有空格。按順序表示地圖中每一行的數據。 N≤100;M≤10。
Output Format
文件僅在第一行包含一個整數K,表示最多能擺放的炮兵部隊的數量。
Sample Input
5 4
PHPP
PPHH
PPPP
PHPP
PHHP
Sample Output
6
- 分析:
- m <= 10
來個愉快地狀壓吧~
①用二進制表示每行的地形( 0:平原P/ 1:山地H)。
②dfs出每行的情況,注意要考慮炮兵的攻擊範圍,情況也壓進二進制 (0:沒放炮兵/ 1:放了炮兵),存在s數組中。
③用鄰接表存儲可以放在相鄰一行和兩行的每行情況。
④轉移方程:
- m <= 10
f[i][j][e[k].to] = max(f[i][j][e[k].to], f[i - 1][e[k].to][e[l].to] + __builtin_popcount(s[j]));
f[i][j][e[k].to] : 枚舉到第i行爲止,第i行情況爲j,第i-1行情況爲e[k].to;
__builtin_popcount(x)函數表示計算二進制數x中1的個數,詳見→神犇的整理
【前幾天剛學的時候還看了挺久的課件才%出來ORZ
- 代碼:
#include <bits/stdc++.h>
using namespace std;
const int MN = 105;
struct info{
int to, next;
}e[MN * MN];
int n, m, num, i, j, k, l, ans, p[MN], s[MN], h[MN], f[MN][MN][MN];
char c[15];
inline void add(int u, int v)
{
e[++ k].to = v;
e[k].next = h[u];
h[u] = k;
}
inline void dfs(int d, int now)
{
if (d == m)
{
s[++ num] = now;
return;
}
dfs(d + 1, now << 1);
if (((now & 1) == 0) && ((now & 2) == 0))
dfs(d + 1, (now << 1) + 1);
}
int main()
{
scanf("%d%d\n", &n, &m);
for(i = 1; i <= n; i ++)
{
scanf("%s\n", c);
p[i] = 0;
for(j = 0; j < m; j ++)
{
p[i] = p[i] << 1;
if (c[j] == 'H')
p[i] += 1;
}
}
//讀入&①
num = 0;
dfs(0, 0);
//②
for(i = k = 1; i <= num; i ++)
for(j = i; j <= num; j ++)
if ((s[i] & s[j]) == 0)
{
add(i, j);
add(j, i);
}
//③
for(i = 0; i <= n; i ++)
for(j = 0; j <= num; j ++)
for(k = 0; k <= num; k ++)
f[i][j][k] = -0x3f3f3f;
f[0][1][1] = 0;
//初始化
for(i = 1; i <= n; i ++)
for(j = 1; j <= num; j ++)
if ((p[i] & s[j]) == 0)//該放法被地形允許
for(k = h[j]; k; k = e[k].next)
for(l = h[j]; l; l = e[l].next)
f[i][j][e[k].to] = max(f[i][j][e[k].to], f[i - 1][e[k].to][e[l].to] + __builtin_popcount(s[j]));
//狀態轉移&④
ans = 0;
for(i = 1; i <= num; i ++)
for(j = 1; j <= num; j ++)
ans = max(ans, f[n][i][j]);
printf("%d", ans);
//統計並輸出答案
return 0;
}
晚上好~ : )