一、状态压缩dp(3)炮兵阵地

3、 炮兵阵地(cannon
【问题描述】
司令部的将军们打算在 N*M 的网格地图上部署他们的炮兵部队。一个N*M的地图由 N
M 列组成,地图的每一格可能是山地(用"H"表示),也可能是平原(用"P"表示),如下图。
在每一格平原地形上最多可以布置一支炮兵部队(山地上不能够部署炮兵部队);一支炮兵
部队在地图上的攻击范围如图中黑色区域所示:
如果在地图中的灰色所标识的平原上部署一支炮兵部队,则图中的黑色的网格表示它能够攻
击到的区域:沿横向左右各两格,沿纵向上下各两格。图上其它白色网格均攻击不到。从图
上可见炮兵的攻击范围不受地形的影响。
现在,将军们规划如何部署炮兵部队,在防止误伤的前提下(保证任何两支炮兵部队之间不
能互相攻击,即任何一支炮兵部队都不在其他支炮兵部队的攻击范围内),在整个地图区域
内最多能够摆放多少我军的炮兵部队。
【输入格式】
第一行包含两个由空格分割开的正整数,分别表示 N M
接下来的 N 行,每一行含有连续的 M 个字符('P'或者'H'),中间没有空格。按顺序表示地图
中每一行的数据。 N <= 100M <= 10
【输出格式】
仅一行,包含一个整数 K,表示最多能摆放的炮兵部队的数量。
【输入样例】
5 4

PHPP

PPHH

PPPP

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.





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值