[pku2411]Mondriaan's Dream

 

 

 

求一个 n*m 的矩形用 1*2 的矩形进行覆盖的方法总数

状态压缩的动态规划

首先进行枚举,枚举出 flag[p][q] 表示 p 状态可以到达 q 状态,那么就可以进行动态规划了, opt[i][s] 可以更新 opt[i+1][k], 其中 flag[s][k]=true ,最后所求

opt[n][max]( 注意初始值

 

opt[0][max]=1)

{
  pku2411 Mondriaan's Dream
  By largelymfs
  Accepted    25840K    1922MS
  Date:2010-05-30 15:05
  状态压缩动态规划
}
Program Ex;
Const
  Infile = 'pku2411.in';
  Outfile = 'pku2411.out';
  maxn=12;
Var
  flag : Array[0..5000, 0..5000] Of Boolean;
  opt : Array[0..maxn, 0..5000] Of int64;
  maxsize, n, m : longint;

Procedure Dfs(pp, qq, k : longint);
var
  tmp : longint;
begin
  If k>m then begin
    flag[pp][qq] := true;
    Exit;
  end;
  if pp And (1 shl (m-k))=0 Then begin
    tmp := qq + 1 shl (m-k);
    //If (k<=m-1) And (pp And (1 shl (m-k-1))<>0) Then dfs(pp, tmp+1 shl (m-k-1), k+2);
    dfs(pp, tmp, k+1);
  end
  Else Begin
    if (k<=m-1) And (pp And (1 shl (m-k-1))<>0) then dfs(pp, qq+1 shl (m-k)+1 shl (m-k-1), k+2);
    dfs(pp, qq, k+1);
  end;
end;

Procedure Prepare;
Var
  i : longint;
begin
  maxsize := (1 shl m)-1;
  Fillchar(flag, sizeof(flag), 0);
  For i := 0 To maxsize Do Dfs(i, 0, 1);
End;
Procedure Main;
var
  i, j, k : longint;
begin
  Fillchar(opt, sizeof(opt), 0);
  opt[0][maxsize] := 1;
  For i := 0 to n-1 Do
    For j := 0 to maxsize Do Begin
      If opt[i][j]=0 then Continue;
      For k := 0 To maxsize Do
        If flag[j][k] then begin
          opt[i+1][k] := opt[i+1][k]+opt[i][j];
        end;
    end;
  writeln(opt[n][maxsize]);
End;

Begin
  Assign(Input, INfile);Reset(input);Assign(Output, OUtfile);Rewrite(Output);
  Readln(n, m);
  While (n<>0) Or (m<>0) Do begin
    Prepare;Main;
    Readln(n, m);
  end;
  Close(Input);Close(Output);
End.
优化

当n<m时交换m,n

如果m,n均为奇数时无解

{
  pku2411 Mondriaan's Dream
  By largelymfs
  Accepted    25876K    1313MS
  Date:2010-05-30 15:05
  状态压缩动态规划
}
Program Ex;
Const
  Infile = 'pku2411.in';
  Outfile = 'pku2411.out';
  maxn=12;
Var
  flag : Array[0..5000, 0..5000] Of Boolean;
  opt : Array[0..maxn, 0..5000] Of int64;
  maxsize, n, m, tt : longint;

Procedure Dfs(pp, qq, k : longint);
var
  tmp : longint;
begin
  If k>m then begin
    flag[pp][qq] := true;
    Exit;
  end;
  if pp And (1 shl (m-k))=0 Then begin
    tmp := qq + 1 shl (m-k);
    dfs(pp, tmp, k+1);
  end
  Else Begin
    if (k<=m-1) And (pp And (1 shl (m-k-1))<>0) then dfs(pp, qq+1 shl (m-k)+1 shl (m-k-1), k+2);
    dfs(pp, qq, k+1);
  end;
end;

Procedure Prepare;
Var
  i : longint;
begin
  maxsize := (1 shl m)-1;
  Fillchar(flag, sizeof(flag), 0);
  For i := 0 To maxsize Do Dfs(i, 0, 1);
End;
Procedure Main;
var
  i, j, k : longint;
begin
  Fillchar(opt, sizeof(opt), 0);
  opt[0][maxsize] := 1;
  For i := 0 to n-1 Do
    For j := 0 to maxsize Do Begin
      If opt[i][j]=0 then Continue;
      For k := 0 To maxsize Do
        If flag[j][k] then begin
          opt[i+1][k] := opt[i+1][k]+opt[i][j];
        end;
    end;
  writeln(opt[n][maxsize]);
End;

Begin
  Assign(Input, INfile);Reset(input);Assign(Output, OUtfile);Rewrite(Output);
  Readln(n, m);
  While (n<>0) Or (m<>0) Do begin
    If (n mod 2=1) And (m mod 2=1) then begin
      writeln(0);
    end
    Else Begin
      If m>n Then Begin tt := m;m := n;n := tt;End;
      Prepare;Main;
    end;
    Readln(n, m);
  end;
  Close(Input);Close(Output);
End.

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值