• POJ 2411_Mondriaan's Dream


    题意:

    用1*2和2*1的方块将给定长宽的矩形填满。问有多少种放法,对称的算两种。

    分析:

    状态压缩dp
    首先用0表示前一行没有竖块占用这个位置,而1表示该位置和他上方的位置放了一个竖块,从而压缩状态。接下来一行一行的看,每一行都只受上一行的影响,同时影响着下一行的状态,那么如何将现在的状态和下一行的状态联系起来呢?

    1. dp[i][j]表示第i行状态为j时的方案数,直接把两个状态作为参数进行DFS,在到达每行行尾时更新 dp[i+1][next];。
    2. 看poj的discuss中的方法,对于某一行来说,如果横着放了方块后,就将相应的位置置为1,而被上一行占用的位置也已经是1了,那么整行下来,就只有0的位置是要放竖块的了,而此时下一行对应的位置应该为1,可以发现下一行状态就是这一行状态的非!【感觉好巧妙啊!

    因为要求正好填满,所以两种方法最后都可以是输出dp[h+1][0],但是第二种方法也就可以取反直接用dp[h][(1<<w)1]求。
    还有!!位运算注意括号!!

    代码:

    方法一:

    #include<cstdio>
    #include<cstring>
    const int maxn = 15;
    long long dp[maxn][1<<maxn];
    int w, h;
    void dfs(int a, int b, int now, int next)
    {
       if(b == w){
            dp[a+1][next] += dp[a][now];
            return;
       }
       if(now&(1<<b)) dfs(a, b + 1, now, next);
       else {
            dfs(a,  b+1, now, next|1<<b);
            if(b+1< w&&!(now&1<<(b+1)))  
                 dfs(a, b+2, now,  next);
       }
        return;
    }
    int main (void)
    {
        while(~scanf("%d%d",&h,&w)&&h+w){
            memset(dp, 0, sizeof(dp));
            dp[1][0] = 1;
            dfs(1,0,0,0);
            for(int i = 2; i <= h; i++){
                for(int j = 0; j < 1<<w; j++){
                    if(dp[i][j]) dfs(i, 0, j, 0);
                }
            }
            printf("%I64d
    ",dp[h+1][0]);
        }
    }//266ms
    

    方法二:

    #include<cstdio>
    #include<cstring>
    const int maxn = 15;
    long long dp[maxn][1<<maxn];
    int w, h;
    long long tmp;
    void dfs(int a, int b, int now)
    {
       if(b == w){
            dp[a][now] += tmp;
            return;
       }
       dfs(a, b + 1,now);//要么被占要么放竖块
       if(b+1<w&&!(now&1<<b)&&!(now&1<<(b+1)))
            dfs(a, b+2, now|(1<<b)|(1<<(b+1)));
        return;
    }
    int main (void)
    {
        while(~scanf("%d%d",&h,&w)&&h+w){
            memset(dp, 0, sizeof(dp));
            tmp = 1;
            dfs(1,0,0);
            for(int i = 2; i <= h; i++){
                for(int j = 0; j < 1<<w; j++){
                   if(dp[i-1][j]) {
                        tmp = dp[i-1][j];
                        int next = ~j&((1<<w)-1);
                        dfs(i, 0, next);
                    }
                }
            }
            printf("%I64d
    ",dp[h][(1<<w)-1]);
        }
    }//250MS
    
  • 相关阅读:
    思维导图
    Delphi 之弹出气泡消息提示
    delphi 响应鼠标进入控件消息
    Delphi 获取当前鼠标下的控件内容
    delphi TTBXToolBar 增加外部控件
    delphi button 实现下拉列表
    delphi 设置多屏幕
    电脑双屏改单屏后看不到文件问题的解决
    delphi ListView 设置固定列宽
    数字孪生(Digital twin)
  • 原文地址:https://www.cnblogs.com/Tuesdayzz/p/5758780.html
Copyright © 2020-2023  润新知