poj 1038 Bugs Integrated, Inc. 状压dp

题意:给出 n*m(n ≤150,m≤10 ) 的棋盘,要在上面放置 2*3 的骨牌,有一些方格无法放置,求最多能放置多少个。

分析:因为每一行的状态都会影响到前两行,所以就用三进制的数记录第i行和第i-1行的状态。f[i,j]表示第i行和第i-1行状态为j时的最大放置数,然后暴力转移就好了。

黑书138已经写的很清楚了,这里就不多说了。

代码:

const
  maxn=59048;

var
  t,l,i,j,k,n,m,p,ans,x,y,g:longint;
  v1,v2:array[1..150,1..10] of boolean;
  a:array[1..20] of longint;
  f:array[0..1,0..maxn] of longint;

function max(x,y:longint):longint;
begin
  if x>y then exit(x)
         else exit(y);
end;

procedure work(x,s,num:longint);
begin
  if x>m+1 then exit;
  if x=m+1 then
  begin
    f[g,s]:=num;
    exit;
  end;
  work(x+1,s*3,num);
  if v2[1,x] then work(x+3,s*27+26,num+1);
end;

procedure dfs(x,s,num:longint);
begin
  if x>m+1 then exit;
  if x=m+1 then
  begin
    if f[1-g,j]+num>f[g,s] then
    begin
      f[g,s]:=f[1-g,j]+num;
      if f[g,s]>ans then ans:=f[g,s];
    end;
    exit;
  end;
  dfs(x+1,s*3+max(a[x]-1,0),num);
  if (v1[i-2,x])and(a[x]=0)and(a[x+1]=0) then dfs(x+2,s*9+8,num+1);
  if (v2[i-1,x])and(a[x]<2)and(a[x+1]<2)and(a[x+2]<2) then dfs(x+3,s*27+26,num+1);
end;

begin
  readln(t);
  for l:=1 to t do
  begin
    readln(n,m,p);
    fillchar(v1,sizeof(v1),true);
    fillchar(v2,sizeof(v2),true);
    for i:=1 to p do
    begin
      readln(x,y);
      for j:=max(x-2,1) to x do
        for k:=max(y-1,1) to y do
          v1[j,k]:=false;
      for j:=max(x-1,1) to x do
        for k:=max(y-2,1) to y do
          v2[j,k]:=false;
    end;
    g:=0;
    for i:=0 to maxn do
      f[g,i]:=-1;
    work(1,0,0);
    ans:=0;
    for i:=3 to n do
    begin
      g:=1-g;
      for j:=0 to maxn do
        f[g,j]:=-1;
      for j:=0 to maxn do
        if f[1-g,j]>-1 then
        begin
          x:=j;
          for k:=m downto 1 do
          begin
            a[k]:=x mod 3;
            x:=x div 3;
          end;
          dfs(1,0,0);
        end;
    end;
    writeln(ans);
  end;
end.


你可能感兴趣的:(poj 1038 Bugs Integrated, Inc. 状压dp)