poj 2411 Mondriaan's Dream 状压dp

给出一个n*m的方阵,求用1*2的多米诺骨牌恰好完全填满有多少种方案。

用f[i,s]表示第i行的状态为s的时候的方案数。s某一位为1表示已放。

f[i,s]=sum(f[i-1,ss])且满足s和ss是兼容的。下面就给出了兼容的条件。

若ss的第i位为0则s的第i位一定为1也就是要竖着放然后i+1,否则不兼容。

若ss的第i位为1且s的第i位为1则s的第i位一定要横着放,也就是仍要满足ss的i+1位和s的i+1位都是1,然后i+2;否则不兼容。

其他情况都是兼容的。

然后对于每种状态判断是否兼容后进行转移就好了。

初始状态:f[0,1 shl m-1]=1

输出f[n,1 shl m-1]。

代码:

var
  n,m,i,j,k:longint;
  f:array[0..11,0..2048] of int64;

function check(x,y:longint):boolean;
var
  i:longint;
begin
  i:=1;
  while i<=m do
  begin
    if (x and 1=0)and(y and 1=0) then exit(false);
    if (x and 1=1)and(y and 1=0)or(x and 1=0)and(y and 1=1) then
    begin
      x:=x shr 1;
      y:=y shr 1;
      inc(i);
      continue;
    end;
    x:=x shr 1;
    y:=y shr 1;
    if (y and 1=0)or(x and 1=0) then exit(false);
    x:=x shr 1;
    y:=y shr 1;
    i:=i+2;
  end;
  check:=true;
end;

begin
  readln(n,m);
  while (n>0)or(m>0) do
  begin
    if n<m then
    begin
      n:=n xor m; m:=n xor m; n:=n xor m;
    end;
    if n*m mod 2=1 then
    begin
      writeln(0);
      readln(n,m);
      continue;
    end;
    fillchar(f,sizeof(f),0);
    f[0,1 shl m-1]:=1;
    for i:=1 to n do
      for j:=0 to 1 shl m-1 do
        for k:=0 to 1 shl m-1 do
          if f[i-1,k]>0 then
            if check(j,k) then
              f[i,j]:=f[i,j]+f[i-1,k];
    writeln(f[n,1 shl m-1]);
    readln(n,m);
  end;
end.


你可能感兴趣的:(poj 2411 Mondriaan's Dream 状压dp)