• POJ2411 蒙德里安的梦想 题解


    题目描述


     

    求把 N×M 的棋盘分割成若干个 1×2 的的长方形,有多少种方案。

    例如当 N=2,M=4 时,共有 5 种方案。当 N=2,M=3 时,共有 3 种方案。

    如下图所示:

     

     

     输入


     

    输入包含多组测试用例。

    每组测试用例占一行,包含两个整数 N 和 M。

    当输入用例 N=0,M=0 时,表示输入终止,且该用例无需处理。

    输出


     

    每个测试用例输出一个结果,每个结果占一行。

     

    输入样例


     

     

    1 2
    1 3
    1 4
    2 2
    2 3
    2 4
    2 11
    4 11
    0 0

     

    输出样例


     

    1
    0
    1
    2
    3
    5
    144
    51205

    数据范围


     

    1N,M11

    题解


     

    这是一道状态压缩dp的入门( 模板)题

    题目大意了解后,我们发现数据范围小的离谱,而这道题的状态非常大,所以我们考虑状压dp

    接下来开始想状态表示和转移方程

    这道题的核心思想就是:

    我们可以先放横的,再放竖的;

    这里我们用  f[i,j] 表示 已经填好了前 i - 1列,考虑从第i - 1列伸到第i列的所有方案数,并且状态为 j

    按照正常的dp思路,我们都是考虑倒数第二个进行思考

    不妨假设前i - 1行的状态为k 那么最后的转移方程显然是 f[i,j] += f[i - 1,k];

    方程想好了考虑合法二字,什么时候合法呢?

    我们容易发现

             1.j & k == 0(不能同时占有一个格子)

             2.所有连续的空格子的长度必须是偶数

     

    只有同时满足上面两个条件才是合法状态;

    我们不妨先预处理出来满足条件2的合法状态,至于条件1,可以在方程转移的时候进行特判

    最后注意一点答案应该是 f[m][0];

     

    代码如下:

    #include<iostream>
    #include <algorithm>
    #include <cstring>
    using namespace std;
    
    const int N = 12,M = 1 << N;
    long long f[N][M];
    bool st[M];
    int n,m;
    
    int main()
    {
        while(cin >> n >> m && (n || m))
        {
            for(int i = 0;i < 1 << n; ++ i)
            {
                int cnt = 0;
                st[i] = true;
                for(int j = 0; j < n; ++ j)
                {
                    if(i >> j & 1)
                    {
                        if(cnt & 1) st[i] = false;
                    }
                    else cnt ++;
                }
                if(cnt & 1) st[i] = false;
            } 
            memset(f,0,sizeof f);
           f[0][0] = 1;
           for(int i = 1; i <= m; ++ i)
              for(int j = 0; j < 1 << n; ++j)
                 for(int k = 0; k < 1 << n; ++ k)
                   if ((j & k) == 0 && (st[j | k])) f[i][j] += f[i - 1][k];
          cout << f[m][0] << endl;
        }
        
        return 0;
    }
     
  • 相关阅读:
    Android实现多个词汇连续输入的提示
    android 中使用AutoCompleteTextView 可以实现自动提示功能
    关于android中搜索功能的实现
    重复弹出Toast 解决方案
    Android显示不重复通知的Notification
    个人项目经历
    使用Google 官方的控件SwipeRefreshLayout实现下拉刷新功能
    安卓左滑实现返回上一个页面
    初学hadoop
    浅谈nodejs和php
  • 原文地址:https://www.cnblogs.com/yjyl0098/p/14620729.html
Copyright © 2020-2023  润新知