洛谷 P2704 [NOI2001]炮兵阵地

题目大意:

给出N*M的地图,有很多空地P跟山地H,炮台可以攻击周边:
洛谷 P2704 [NOI2001]炮兵阵地_第1张图片
求最多能放多少个炮台并且他们互不攻击。

N≤100;M≤10

题解:

这题是状压dp的一道经典题目,
对于每行10个东东可以放就是2^10种可能,这样转移就会TLE
所以我们发现因为任意2个炮之间距离至少为2,所以我们每行存在的可行状态至多不超过2^5
因此我们暴力处理出每行的这些状态以及
每个状态存在多少个炮台即可。
然后去dp即可
设f[i,k,j]表示选到了第i行,第i行状态为s[k],第i-1行状态为s[j]时的最大能放数量。
推得转移方程:
f[i,k,j]=max{f[i,k,j],f[i-1,j,l]+num[s[i]]}
l为i-2行的状态
注意判断第i,i-1,i-2行的状态是否冲突

代码:

var
     f:array [-5..101,0..61,0..61] of longint;
     s:array [-5..101,0..61] of longint;
     a:array [0..101,0..11] of char;
     num,c:array [0..1025] of longint;
     b:array [0..11] of longint;
     ans,ans1,i,j,k,l,p,n,m:longint;
     check:boolean;

function max(aa,bb:longint):longint;
begin
     if aa>bb then exit(aa);
     exit(bb);
end;

procedure dfs(dep,now,cp:longint);
var
     j:longint;
begin
     if c[now]<>i then
        begin
            c[now]:=i;
            if num[now]=0 then num[now]:=cp;
            inc(s[i,0]);
            s[i,s[i,0]]:=now;
        end;
     if dep=m then exit;
     for j:=dep+1 to m do
       if (a[i,j]='P') and (b[j]<>i) then
       begin
             b[j+1]:=i;
             b[j+2]:=i;
             dfs(j,now+1 shl (j-1),cp+1);
             b[j+1]:=0;
             b[j+2]:=0;
       end;
     dfs(dep+1,now,cp);
end;


begin
     readln(n,m);
     for i:=1 to n do
       begin
            for j:=1 to m do read(a[i,j]);
            dfs(0,0,0);
            readln;
       end;
     ans:=0;
     for i:=1 to s[1,0] do
        f[1,i,1]:=num[s[1,i]];

     s[0,0]:=1; s[0,1]:=0;

     for i:=2 to n do

       for j:=1 to s[i,0] do

          for k:=1 to s[i-1,0] do

            if s[i,j] and s[i-1,k]=0 then

                for l:=1 to s[i-2,0] do

                  if s[i-2,l] and s[i,j]=0 then

                     if s[i-2,l] and s[i-1,k]=0 then
                        begin
                             f[i,j,k]:=max(f[i,j,k],f[i-1,k,l]+num[s[i,j]]);
                             ans:=max(ans,f[i,j,k]);
                        end;
     writeln(ans);
end.

你可能感兴趣的:(pascal,状压dp)