题意很简单,用1*2的小矩形不重叠也不漏地铺满n*m的矩形,问方案数.
解法自然是状态压缩DP.
考虑每一行,用一个二进制串表示其状态,若第i位为1则表示在这一行的第i列竖放一个矩形,
它占用了这一行和下一行的第i列(下一行的第i列为0).其余的0表示横放的矩形.
具体做法:用f[i,j]表示第i行放置方法为j(j是二进制数)的方案数.
显然第一行的二进制串中不能出现连续的奇数个.
对于第i行的二进制串now,第i-1行的二进制串pre,它们应该满足now and pre=0,
且now or pre中也不能含连续奇数个0.
对于最后一行,只要上一行的二进制串中不含连续奇数个0即可.
code:
var p:array[1..11,0..2500] of longint; f:array[1..11,0..2500] of int64; n,m:longint; function check(num,mm:longint):boolean; var sum:longint; begin sum:=0; num:=num+1<<mm; while num>0 do begin if num and 1=0 then inc(sum) else if sum and 1=1 then exit(false) else sum:=0; num:=num>>1; end; if sum and 1=1 then exit(false) else exit(true); end; procedure prepare; var O:longint; begin for M:=1 to 11 do for O:=0 to 1<<M-1 do if O=0 then begin if M and 1=0 then inc(p[m,0]) end else if check(O,M) then begin inc(p[m,0]); p[m,p[m,0]]:=o; end; end; function DP(n,m:longint):int64; var i,j,k:longint; ans:int64; begin fillchar(f,sizeof(f),0); ans:=0; for i:=1 to p[m,0] do f[1,p[m,i]]:=1; for i:=2 to n-1 do for j:=0 to 1<<M-1 do if f[i-1,j]>0 then for k:=0 to 1<<M-1 do if (k and j=0)and(check(k or j,m)) then f[i,k]:=int64(f[i,k])+int64(f[i-1,j]); for j:=0 to 1<<M-1 do if f[n-1,j]>0 then if check(j,m) then ans:=int64(ans)+int64(f[n-1,j]); exit(ans); end; begin prepare; while not eof do begin readln(n,m); if n+m=0 then halt; if ((n and m) and 1)=1 then begin writeln(0); continue; end else if n=1 then begin writeln(1); continue; end else writeln(DP(n,m)); end; end.
类似的题目还有POJ1185,POJ3254.