【动态规划】炮兵阵地

问题

还是宇宙时间公元 5.5 5.5亿年, maxingc maxingc maxingc maxingc联盟用微子来攻击 yunyunyun联盟。愤怒的 yunyun 联盟决定反戈一击,他们 准备使用加农炮来反击。
yunyun 联盟的将军们打算在 N*M 的网格地图上部署他们炮兵队。一个 的网格地图上部署他们炮兵队。一个 N*M 的地图由 N行 M列组成,地 列组成,地 图的每一格可能是山地(用 图的每一格可能是山地(用 "H" "H" 表示),也可能是平原(用 表示),也可能是平原(用 表示),也可能是平原(用 表示),也可能是平原(用 "P" "P"表示),如下图。在每一格平原 表示),如下图。在每一格平原 表示),如下图。在每一格平原 表示),如下图。在每一格平原 地形上最多可 以布置一支炮兵部队(山地上不能够署);在图的攻击范围如中黑色区域所 以布置一支炮兵部队(山地上不能够署);在图的攻击范围如中黑色区域所 以布置一支炮兵部队(山地上不能够署);在图的攻击范围如中黑色区域所 以布置一支炮兵部队(山地上不能够署);在图的攻击范围如中黑色区域所 示:

如果在地图中的灰色所标识平原上部署一支炮兵队,则黑网格表示它能够攻击到区域:沿横向左右各两格,纵上下。图其它白色网均攻击不到从可见炮兵的范围受地形的影响。 现在,将军们规划如何部署炮兵队防止误伤的 前提下(保证任何两支炮兵部队之间不能互相攻击, 即任何一支炮 兵部队都不在其他的攻击范围内),整个地图区域最多能够摆放少我军即任何一支炮 兵部队都不在其他的攻击范围内),整个地图区域最多能够摆放少我军即任何一支炮 兵部队都不在其他的攻击范围内),整个地图区域最多能够摆放少我军兵部队。
第一行包含两个由空格分割开的正整数,别表示 N和 M; 接下来的 N行,每一含有连续的 行,每一含有连续的 M个字符 ('P'('P' 或者 'H') 'H') ,中间没有空格。 按顺序表示地图每一行的数据,中间没有空格。 按顺序表示地图每一行的数据,中间没有空格。 按顺序表示地图每一行的数据,中间没有空格。 按顺序表示地图每一行的数据N <= 100= 100= 100 ;M <= 10 。
仅一行,包含个整数 K,表示最多能摆放的炮兵部队数量。
分析

这个题的n<=100 ,m<=10。如果盲目搜索,肯定会超时。

由于m<=10,所以每一行的状态可以用二进制表示,放置炮兵记为1,不放置记为0。

每一行的状态只和前两行的状态有关系,所以有方程:

F[i,k1,k2]=Max{f[i-1,k2,k3]+num[k1]},其中i为行数,k1表示第i行的状态,k2表示第i-1行的状态,k3表示第i-2行的状态,num[k1]为k1状态下可放置炮兵的个数。

i,k1,k2,k3必须满足一定的关系(炮兵之间不能相互攻击,且炮兵不能放在山地上)。

1

第i行放第k1种状态,第i-1行放第k2种状态,会不会出现矛盾

对于状态a[k1]和a[k2],如果他们是可行的,讨论他们每个对应的位置

a[k1]如果某位置是1,a[k2]这位上必须是0

a[k1]如果某位置是0,a[k2]这位上可以是1,也可以是0

所以可以归纳出 a[k1] and a[k2]=0,这要判断矛盾可以使速度大大提高

2.

对于每一行,第i种状态能不能放上去,即要求不能在‘H’的地方放士兵

我们可以先把每行原来的初始状态也表示出来,但是这里有个小技巧,把‘H’的地方记录下来

这行如果某位置是1,那么在a[k1]中这个位置上必须为0(1代表这里是山地)

这行如果某位置是0,那么在a[k1]中这个位置上可以为1,可以为0(0代表这里是平原)

所以可以归纳出 now[i] and a[k1]=0(now数组表示地形的状态)。

3.

我们可以提前枚举每种状态,把本身一行中可以相互攻击的状态删去,对于每一行进行操作时,需要将其转化成字符串,否则对一个二进制串很难操作。

此时f数组下表表示的是此状态在状态数组a中的位置。

View Code
program liukeke;
var
now:
array[0..101] of longint;
a,b:
array[0..102] of longint;
f:
array[0..100,0..102,0..102] of longint;
n,m,i,k1,k2,k3,ans,j,tt,sum:longint;
s:string;
flag:boolean;

function max(a,b:longint):longint;
begin
if a>b then exit(a);
exit(b);
end;

procedure init;
var
i,j:longint;
ch:char;
begin
readln(n,m);
for i:=1 to n do
begin
for j:=1 to m do
begin
read(ch);
if ch='H' then
now[i]:
=now[i] + (1<<(m-j));
end;
readln;
end;
end;

function change(x:longint):string;
begin
change:
='';
while x>0 do
begin
change:
=chr(x mod 2+48)+change;
x:
=x div 2;
end;
end;

begin
assign(input,
'connon.in');
reset(input);
assign(output,
'connon.out');
rewrite(output);
init;
for i:=0 to (1<<m)-1 do
begin
tt:
=0;
flag:
=false;
s:
=change(i);
while length(s)<m do s:='0'+s;
for j:=1 to m do
if s[j]='1' then
begin
if s[j+1]='1' then begin flag:=true; break; end;
if s[j+2]='1' then begin flag:=true; break; end;
inc(tt);
end;
if not flag then
begin
inc(sum);
a[sum]:
=i;
b[sum]:
=tt;
end;
end;
for i:=1 to sum do
f[
1,i,1]:=b[i];
for i:=2 to n do
for k1:=1 to sum do
for k2:=1 to sum do
if (a[k1] and a[k2]=0)and(a[k1] and now[i]=0)and(a[k2] and now[i-1]=0)then
for k3:=1 to sum do
if (a[k1] and a[k3]=0)and(a[k2] and a[k3]=0)and(a[k3] and now[i-2]=0)then
f[i,k1,k2]:
=max(f[i,k1,k2],f[i-1,k2,k3]+b[k1]);
for i:=1 to sum do
for j:=1 to sum do
if (a[i]and a[j]=0)and(a[i] and now[n]=0)and(a[j] and now[n-1]=0)then
ans:
=max(ans,f[n,i,j]);
writeln(ans);
close(input);
close(output);
end.
posted @ 2011-06-12 19:33  liukee  阅读(890)  评论(0编辑  收藏  举报