问题
还是宇宙时间公元 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中的位置。
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 .