【问题描述】
司令部的将军们打算在 N*M 的网格地图上部署他们的炮兵部队。一个N*M的地图由 N 行
M 列组成,地图的每一格可能是山地(用"H"表示),也可能是平原(用"P"表示),如下图。
在每一格平原地形上最多可以布置一支炮兵部队(山地上不能够部署炮兵部队);一支炮兵
部队在地图上的攻击范围如图中黑色区域所示:
如果在地图中的灰色所标识的平原上部署一支炮兵部队,则图中的黑色的网格表示它能够攻
击到的区域:沿横向左右各两格,沿纵向上下各两格。图上其它白色网格均攻击不到。从图
上可见炮兵的攻击范围不受地形的影响。
现在,将军们规划如何部署炮兵部队,在防止误伤的前提下(保证任何两支炮兵部队之间不
能互相攻击,即任何一支炮兵部队都不在其他支炮兵部队的攻击范围内),在整个地图区域
内最多能够摆放多少我军的炮兵部队。
【输入格式】
第一行包含两个由空格分割开的正整数,分别表示 N 和 M;
接下来的 N 行,每一行含有连续的 M 个字符('P'或者'H'),中间没有空格。按顺序表示地图
中每一行的数据。 N <= 100;M <= 10。
【输出格式】
仅一行,包含一个整数 K,表示最多能摆放的炮兵部队的数量。
【输入样例】
5 4
PHPP
PPHHPPPP
PHPP
PHHP
【输出样例】
6
分析:
经典状态压缩DP。(代码有注释);
代码:
var
g:array[1..100,1..100] of longint;
ff:array[1..100,1..100] of longint;
f:array[1..100,1..100,1..100] of longint;
a:array[1..100,1..10] of char;
d:array[1..100] of longint;
i,j,k,l,maxn,m,n,tot,sum,ans:longint;
function max(x,y:longint):longint;
begin
if x>y then
exit(x);
exit(y);
end;
procedure dfs(x:longint);//深搜找每一行可行状态
begin
if x>m then
begin
inc(tot);
g[i,tot]:=sum;
ff[i,tot]:=ans;
d[i]:=tot;
exit;
end;
if a[i,x]='P' then
begin
sum:=sum+1<<(x-1);
inc(ans);
dfs(x+3);
sum:=sum-1<<(x-1);
dec(ans);
end;
dfs(x+1);
end;
procedure make;//特殊处理第2行,f[2,j,k]=max(ff[2,j]+ff[1,k])
begin
for i:=1 to d[2] do
for j:=1 to d[1] do
if (g[1,j] and g[2,i]=0) then
f[2,i,j]:=ff[2,i]+ff[1,j];
end;
procedure dp;//动态转移方程f[i,j,k]=max(f[i,j,k],f[i-1,k,l]+ff[i,j])
begin
for i:=3 to n do
for j:=1 to d[i] do
for k:=1 to d[i-1] do
for l:=1 to d[i-2] do
if (g[i,j] and g[i-1,k]=0) then
if (g[i,j] and g[i-2,l]=0) then
if (g[i-1,k] and g[i-2,l]=0) then
f[i,j,k]:=max(f[i,j,k],f[i-1,k,l]+ff[i,j]);
end;
begin
assign(input,'cannon.in');
assign(output,'cannon.out');
reset(input);
rewrite(output);
readln(n,m);
for i:=1 to n do
begin
for j:=1 to m do
read(a[i,j]);
readln;
end;
fillchar(f,sizeof(f),0);
for i:=1 to n do
begin
tot:=0;
sum:=0;
ans:=0;
dfs(1);
end;
make;
dp;
maxn:=-(maxlongint>>1);
for i:=1 to d[n] do
for j:=1 to d[n-1] do
if f[n,i,j]>maxn then
maxn:=f[n,i,j];
writeln(maxn);
close(input);
close(output);
end.