这题真没想出来有这么复杂,当然对我们新手来说,没状态压缩的意识,对位运算不理解,害得我看别人代码都想了半天...
首先这题是一道关于状态压缩dp
f(i,j) 表示 第i行 状态为j 的个数 <怎么理解状态 j 呢? 二进制思想,假设一行有m个单位需要填充,我们就可以用0 or 1
来表示每一个单位上的属性【0 代表 1x2 单位是横放的不影响下一行,1 代表 1x2 是竖放的影响下一行就是表示下一行对应的
单位已经被填充了】 >
解题中我们可以枚举每一行每一个状态,即由上一行的状态能到达此状态的个数和。
//
void dfs(int i, int j, int jj, int s) // s 为 当前到达的位置,即需要判断每一行的每一个需要填充的状态为1 or 0
{
    if (s == m) // 一行完整状态产生了
        f[i + 1][jj] += f[i][j]; // 累加每一次可以到达此状态的个数<取决于上一行的状态>
    else if ((jj & (1 << s)) == 0)  // 判断 上一行在 s 位置上的状态为 0 
    {
        dfs(i, j, jj | (1 << s), s + 1); // 在 s 位置 置1(jj | 1<<s)<竖放> 
        if (s < m - 1 && (jj & (1 << (s + 1))) == 0) dfs(i, j, jj, s + 2); // 判断在 s+1 位置上状态是否为
        // 0 ,是则 横放
    }
    else
        dfs(i, j, jj & ~(1 << s), s + 1); // 置 s 状态为 0 , jj & ~(1<<s)
}
<源代码 自己去百度...>
ps: 一些对位运算不怎么熟悉的同学可以到纸上YY一下就知道了,也有些同学对状态的改变不是很清楚<至少但是我看了一份源码之后没有那种清晰的感觉>......
首先 jj 是目标状态 , jj = j 继承上一行的状态,但是为什么能转化成自己的状态呢?
因为我们每一步都是按照 s 即位置来算的< 每一个小状态都是 s 决定 >,所以我们改变的状态也是一步一步进行的,我们既可以利用jj
来判断那些还没有经过的位置相对应的上一行的状态< jj & 1<<s 这时在s位置前面的状态就是我们所生成的 ,但是s位置后面的我们还
没有进行判断> , 总而言之jj这个状态是由每一行的小状态决定的.
 posted on 2011-05-19 21:16  eth0  阅读(157)  评论(0编辑  收藏  举报