Viaky
Hope,is there.

所谓状态压缩型动态规划,就是将不方便转移或数据量极大的状态用01字串来表示,这样就可以方便的转移状态,同时节省了大量的空间。

规定三种砖:1*2的矩形,2*2的正方形,2*2的正方形去掉一个1*1的正方形,给出棋盘的长和宽,输出有多少种铺砖方案。

首先分析题目,对于棋盘上的每一个格子,都有铺和不铺两种状态,于是想到可以用0和1来表示铺与不铺,阶段划分为每一行,这样每一行的状态就被表示为一个数字,其中位运算的应用也很重要。

初始化利用dfs求出从00……01……11的各种行的状态之间的关系,即由某一种状态可以用多少种不同的状态推出下一种状态。枚举出上一行的所有状态,DFS时记录当前的下标,即记录当前已经处理到了行的第几列,用一个数now记录下一行的状态。根据所枚举的上一行的固定状态来修改now的形态。

比如:i为当前上一行的状态,step记录步数,如果当前位置不能放(1<<(step-1) and 1<>0),那么直接将now状态转移给step+1,如果当前位置能放:

1.istep+1位能放,则1)横放一个1*2的砖。2)若nowstep位能放,就放砖三。3)若nowstep+1位能放,就调转砖三的位置放入。4)若nowstep位和step+1位都能放,就放2*2的砖。

2.nowstep位能放:1)竖放一个1*2的砖。2)若nowstep+1位能放,则倒着放砖三。3)若nowstep-1位能放,则放砖三。

由此推出了7中砖的摆放方式,当dfsstep值等于m+1时代表当前i行已经都放完,g[i,now]+1即可。

最后用递推式求出状态总数,各种状态之间是相乘的关系。

F[i,j]:=f[i,j]+f[i,k]*g[k,j];   i行由k状态推到j状态。

注意由于最初是由f[0,0]推来,最后的输出是f[n,0],即棋盘外的第一行没有放。不能输出f[n-1,1<<m-1],因为棋盘最末行满的状态下,下一行可能突出几块砖。

 

Viaky原创。即使写的不好也请尊重作者哦^-^

 1 var
2 n,m,i,j,k:longint;
3 f:array[0..9,0..1024] of int64;
4 g:array[0..1024,0..1024] of int64;
5 procedure dfs(step,now:longint);
6 begin
7 if step=m+1 then
8 begin
9 inc(g[i,now]);
10 exit;
11 end;
12 if 1<<(step-1) and i<>0 then dfs(step+1,now)
13 else
14 begin
15 if (1<<step and i=0) and (step<=m-1) then
16 begin
17 dfs(step+2,now);
18 if (1<<(step-1)) and now=0 then dfs(step+2,now+1<<(step-1));
19 if (1<<step) and now=0 then dfs(step+2,now+1<<step);
20 if (1<<(step-1)) and now=0 then
21 if (1<<step) and now=0 then
22 dfs(step+2,now+1<<step+1<<(step-1));
23 end;
24 if 1<<(step-1) and now=0 then
25 begin
26 dfs(step+1,now+1<<(step-1));
27 if ((1<<step) and now=0) and (step<m) then
28 dfs(step+1,now+1<<step+1<<(step-1));
29 if (1<<(step-2) and now=0) and (step>1) then
30 dfs(step+1,now+1<<(step-1)+1<<(step-2));
31 end;
32 end;
33 end;
34 begin
35 assign(input,'diamonds.in');
36 assign(output,'diamonds.out');
37 reset(input);
38 rewrite(output);
39 readln(n,m);
40 for i:=0 to 1<<m-1 do
41 dfs(1,0);
42 f[0,0]:=1;
43 for i:=1 to n do
44 for j:=0 to 1<<m-1 do
45 for k:=0 to 1<<m-1 do
46 inc(f[i,j],f[i-1,k]*g[k,j]);
47 writeln(f[n,0]);
48 close(input);
49 close(output);
50 end.

posted on 2011-08-10 21:15  Viaky  阅读(3161)  评论(0编辑  收藏  举报