[COGS301] [NOI2001] 炮兵阵地

传送门

http://cojs.tk/cogs/problem/problem.php?pid=301

题目大意

给定01棋盘,1可以放炮兵,每个炮兵间x和y轴距离大于等于2,询问最多放几个

题解

状压DP
根据[BZOJ1725] [Usaco2006 Nov]Corn Fields牧场的安排就可以设计出相似的状态(那道题是相隔1位,这个是相隔2位)
dp[i,j,k]:ij,i1k
dp[i,j,k]=max(dp[i1,k,l]+sum[j],dp[i,j,k])
我们要预处理出所有状态,我们会发现,状态最多有60种…
O(n603)

var
 x:array[0..200,0..20]of longint;
 sum,y:array[0..200]of longint;
 z:array[0..200,0..100]of longint;
 dp:array[0..200,0..200,0..200]of longint;
 i,j,k,l:longint;
 n,m,t,ans:longint;
 cha:char;
function max(a,b:longint):longint;
begin
 if a>b then exit(a) else exit(b);
end;

procedure prepare;
var a,b,c,d,summ:longint;
begin
 t:=1;
 for i:=0 to (1<<m)-1 do
  begin
   l:=1; summ:=0;
   for j:=1 to m do
    begin
     a:=0; b:=0; c:=0; d:=0;
     if i and(1<<(j-1))=0 then continue else inc(summ);
     if j-1>0 then a:=i and(1<<(j-2));
     if j-2>0 then b:=i and(1<<(j-3));
     if j+1<=m then c:=i and(1<<(j));
     if j+2<=m then d:=i and(1<<(j+1));
     if (a<>0)or(b<>0)or(c<>0)or(d<>0) then begin l:=0; break; end;
    end;
   if l=1 then begin y[t]:=i; sum[t]:=summ; inc(t); end;
  end;
 dec(t);
 for i:=1 to n do
  for j:=1 to t do
   begin
    z[i,j]:=1;
    for k:=1 to m do
     if (y[j] and(1<<(k-1))<>0)and(x[i,k]=0)
     then begin z[i,j]:=0; break; end;
   end;
 for j:=1 to t do
  for k:=1 to t do
   if (z[2,j]=1)and(z[1,k]=1)and(y[j]and y[k]=0)
   then dp[2,j,k]:=sum[j]+sum[k];
end;

begin
 readln(n,m);
 for i:=1 to n do
  begin
   for j:=1 to m do
    begin read(cha); if cha='P' then x[i,j]:=1 else x[i,j]:=0; end;
   readln;
  end;
 prepare;
 for i:=3 to n do
  for j:=1 to t do
   if z[i,j]=1 then
   for k:=1 to t do
    if z[i-1,k]=1 then
    for l:=1 to t do
     if (z[i-2,l]=1)and(y[l] and y[k]=0)and((y[l] or y[k])and y[j]=0)
     then dp[i,j,k]:=max(dp[i,j,k],dp[i-1,k,l]+sum[j]);
 ans:=0;
 for i:=1 to t do
  for j:=1 to t do
   ans:=max(ans,dp[n,i,j]);
 writeln(ans);
end.

你可能感兴趣的:([COGS301] [NOI2001] 炮兵阵地)