JZOJ 1768. [NOI2001]炮兵阵地

Description

  司令部的将军们打算在N*M的网格地图上部署他们的炮兵部队。一个N*M的地图由N行M列组成,地图的每一格可能是山地(用“H” 表示),也可能是平原(用“P”表示),如下图。在每一格平原地形上最多可以布置一支炮兵部队(山地上不能够部署炮兵部队);一支炮兵部队在地图上的攻击范围如图中黑色区域所示: 这里写图片描述
   如果在地图中的灰色所标识的平原上部署一支炮兵部队,则图中的黑色的网格表示它能够攻击到的区域:沿横向左右各两格,沿纵向上下各两格。图上其它白色网格均攻击不到。从图上可见炮兵的攻击范围不受地形的影响。   现在,将军们规划如何部署炮兵部队,在防止误伤的前提下(保证任何两支炮兵部队之间不能互相攻击,即任何一支炮兵部队都不在其他支炮兵部队的攻击范围内),在整个地图区域内最多能够摆放多少我军的炮兵部队。

Input

  文件的第一行包含两个由空格分割开的正整数,分别表示N和M;   接下来的N行,每一行含有连续的M个字符(‘P’或者‘H’),中间没有空格。按顺序表示地图中每一行的数据。  数据范围:N≤100;M≤10。

Output

  文件仅在第一行包含一个整数K,表示最多能摆放的炮兵部队的数量。

Sample Input

5 4
PHPP
PPHH
PPPP
PHPP
PHHP

Sample Output

6

Solution

我们先预处理ff[i,j]表示第i行,第j个状态(其中状态是指在这一行中该怎么部署军队,哪里部署那里不能部署)此时还要准备一个数组c,表示这个状态的具体部署情况,用一个2进制数表示。如第一列和第四列部署(此时M=4),则c[i,**]=(1001)2=9
DP用的F[i,j,k]表示第i行,j表示第i行第j个状态,k表示第i-1行第k个状态,再枚举一个l,表示第i-2行第l个状态。第二行的状态是要特判的,因为这个状态只是由第一行转移而来。状态转移方程为
f[2,j,k]=max(f[2,j,k],ff[2,j]+ff[1,k])
其余的动态转移方程为
f[i,j,k]=max(f[i,j,k],f[i-1,k,l]+ff[i,j])
答案则枚举最后两行的所有状态,取最大值。

Code

var a:array[0..101,0..10] of char;
    f:array[0..101,0..100,0..100] of longint;
    ff,c:array[0..101,0..100] of longint;
    e:array[-2..101] of longint;
    _2:array[0..11] of longint;
    i,j,k,l,n,m,t,x,y,ans,s,tot:longint;
    ch:char;
    ss:string;
function max(a,b:longint):longint;
begin
    if a>b then exit(a) else exit(b);
end;
procedure dfs(i,x,s,v:longint);
begin
    if x>m then
    begin
        inc(tot);
        c[i,tot]:=s;
        ff[i,tot]:=v;
        ff[i,0]:=tot;
        exit;
    end;
    if a[i,x]='P' then dfs(i,x+3,s+_2[x-1],v+1);
    dfs(i,x+1,s,v);
end;
begin
    _2[0]:=1;
    for i:=1 to 11 do _2[i]:=_2[i-1]*2;
    readln(n,m);
    for i:=1 to n do
    begin
        for j:=1 to m do read(a[i,j]);
        readln;
    end;
    for i:=1 to n do
    begin
        tot:=0;
        dfs(i,1,0,0);
    end;
    for j:=1 to ff[2,0] do
        for k:=1 to ff[1,0] do
            f[2,j,k]:=max(f[2,j,k],ff[2,j]+ff[1,k]);
    for i:=3 to n do
        for j:=1 to ff[i,0] do
            for k:=1 to ff[i-1,0] do
                for l:=1 to ff[i-2,0] do
                    if (c[i,j] and c[i-1,k]=0) and (c[i,j] and c[i-2,l]=0) and
                       (c[i-1,k]and c[i-2,l]=0) then
                    f[i,j,k]:=max(f[i,j,k],f[i-1,k,l]+ff[i,j]);
    ans:=0;
    for i:=1 to ff[n,0] do
        for j:=1 to ff[n-1,0] do ans:=max(ans,f[n,i,j]);
    writeln(ans);
end.

Special

这道题是一道状压DP,让我们在以后的日子中想到这种类似的解法。
——2016.1.24

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值