所谓状态压缩型动态规划,就是将不方便转移或数据量极大的状态用01字串来表示,这样就可以方便的转移状态,同时节省了大量的空间。
规定三种砖:1*2的矩形,2*2的正方形,2*2的正方形去掉一个1*1的正方形,给出棋盘的长和宽,输出有多少种铺砖方案。
初始化利用dfs求出从00……0到1……11的各种行的状态之间的关系,即由某一种状态可以用多少种不同的状态推出下一种状态。枚举出上一行的所有状态,DFS时记录当前的下标,即记录当前已经处理到了行的第几列,用一个数now记录下一行的状态。根据所枚举的上一行的固定状态来修改now的形态。
比如:i为当前上一行的状态,step记录步数,如果当前位置不能放(1<<(step-1) and 1<>0),那么直接将now状态转移给step+1,如果当前位置能放:
1.若i的step+1位能放,则1)横放一个1*2的砖。2)若now的step位能放,就放砖三。3)若now的step+1位能放,就调转砖三的位置放入。4)若now的step位和step+1位都能放,就放2*2的砖。
2.若now的step位能放:1)竖放一个1*2的砖。2)若now的step+1位能放,则倒着放砖三。3)若now的step-1位能放,则放砖三。
由此推出了7中砖的摆放方式,当dfs的step值等于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.