经典的状态压缩DP。f[i][j]表示第i行,方格排布为二进制数j(第k位上为1表示凸出一个格子,为0表示不凸出)的方案数。用DFS进行状态转移。
如果行数比较多的话,可以用矩阵乘法优化。因为每行的状态转移都是相同的。设烈数为m,行数为n,可以做到O(23mlogn)。

/*************************************************************************
Author: WHU_GCC
Created Time: 2007-8-28 20:53:12
File Name: pku2411.cpp
Description: 
***********************************************************************
*/

#include 
<iostream>
long long f[12][2048], n, m;
void dfs(int i, int j, int jj, int s)
{
    
if (s == m)
        f[i 
+ 1][jj] += f[i][j];
    
else if ((jj & (1 << s)) == 0)
    
{
        dfs(i, j, jj 
| (1 << s), s + 1);
        
if (s < m - 1 && (jj & (1 << (s + 1))) == 0) dfs(i, j, jj, s + 2);
    }

    
else
        dfs(i, j, jj 
& ~(1 << s), s + 1);
}

int main()
{
    
while (scanf("%d%d"&n, &m), n + m != 0)
    
{
        memset(f, 
0sizeof(f));
        f[
0][0= 1;
        
for (int i = 0; i < n; i++)
            
for (int j = 0; j < (1 << m); j++)
                
if (f[i][j])
                    dfs(i, j, j, 
0);
        printf(
"%I64d\n", f[n][0]);
    }

    
return 0;
}
posted on 2007-08-28 21:03 Felicia 阅读(1399) 评论(12)  编辑 收藏 引用 所属分类: 动态规划
Comments
  • # re: [动态规划]pku2411
    ACLover
    Posted @ 2007-09-20 12:45
    可不可以讲下具体怎么状态转移啊,
    太精简了,看不懂。  回复  更多评论   
  • # re: [动态规划]pku2411
    Felicia
    Posted @ 2007-09-20 18:27
    @ACLover
    呵呵,这么简单,你一定想的通的  回复  更多评论   
  • # re: [动态规划]pku2411
    啊水电费
    Posted @ 2007-10-09 23:05
    if (s < m - 1 && (jj & (1 << (s + 1))) == 0) dfs(i, j, jj, s + 2);
    这句话没有看懂!  回复  更多评论   
  • # re: [动态规划]pku2411
    啊水电费
    Posted @ 2007-10-09 23:06
    如果前一行状态对应的位是0,下一行对应位可以取0or1?  回复  更多评论   
  • # re: [动态规划]pku2411
    Felicia
    Posted @ 2007-10-10 08:48
    @啊水电费
    就这两种状态转移,分别对应横着放和竖着放
    00 -> 00
    0 -> 1  回复  更多评论   
  • # re: [动态规划]pku2411[未登录]
    jiushiwo
    Posted @ 2007-10-12 09:11
    #include <iostream>
    long long f[12][2048], n, m;
    void dfs(int i, int j, int jj, int s)
    {
    if (s == m)
    f[i + 1][jj] += f[i][j];
    else if ((jj & (1 << s)) == 0)
    {
    dfs(i, j, jj | (1 << s), s + 1);
    if (s < m - 1 && (jj & (1 << (s + 1))) == 0) dfs(i, j, jj, s + 2);
    }
    else
    dfs(i, j, jj & ~(1 << s), s + 1); //为什么上一层是1,下一层直接置0呢?为什么不考虑置1的情况?
    }
    int main()
    {
    while (scanf("%d%d", &n, &m), n + m != 0)
    {
    memset(f, 0, sizeof(f));
    f[0][0] = 1;
    for (int i = 0; i < n; i++)
    for (int j = 0; j < (1 << m); j++)
    if (f[i][j])
    dfs(i, j, j, 0);
    printf("%I64d\n", f[n][0]);
    }
    return 0;
    }  回复  更多评论   
  • # re: [动态规划]pku2411
    Felicia
    Posted @ 2007-10-12 17:35
    @jiushiwo
    1表示已经放了,不能放了,0表示还能放。  回复  更多评论   
  • # re: [动态规划]pku2411
    zlone
    Posted @ 2007-11-05 22:51
    如何理解横放与竖放与不放3种状态的2进制表示呢
    想了一晚上试了好多方法不见效,奢望指点一二  回复  更多评论   
  • # re: [动态规划]pku2411
    Felicia
    Posted @ 2007-11-06 13:46
    @zlone
    画个图想想,不要考虑怎么放,要考虑放后的形状  回复  更多评论   
  • # re: [动态规划]pku2411
    loveacm
    Posted @ 2007-12-03 17:08
    小弟愚笨,请问jj代表什么意思  回复  更多评论   
  • # re: [动态规划]pku2411
    Felicia
    Posted @ 2007-12-03 17:51
    j是初始状态,jj是目标状态  回复  更多评论   
  • # re: [动态规划]pku2411
    loveacm
    Posted @ 2007-12-03 18:15
    谢谢,另外,请问第k位上为1表示凸出一个格子,为0表示不凸出的方案数,这个凸出如何理解?您的1并不表示竖放,0并不表示横放吧?  回复  更多评论   

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理