DP(状压专题二)

题意 : 给定矩形的长宽, 要求用1*2的矩形有多少种方法摆法能密铺掉原来的矩形

>> face <<

Strategy:状压DP, i是一个表示二进制的十进制数,'1’标记每个竖着放置的矩形的上半部分 其他情况标记为0

状态: dp[i][r] -> 密铺到第r行, 状态i所对应的摆法

目标: dp[0][n] -> 最后一行全0

边界: dp[0][0] = 1;

合法判断: 当上行的状态’j’,下行的状态’i’, j & i == 0(不存在上面一个1下面也是1), i | j 连续的0必须是偶数(两个竖着的矩形之间只能夹着偶数个0)

转移方程:

d p [ i ] [ r ] = d p [ j ] [ r − 1 ] dp[i][r] = dp[j][r-1] dp[i][r]=dp[j][r1]

attention: 可以预处理出每个合法的状态,

双倍经验: 注意枚举的边界

#include <bits/stdc++.h>
// #include<bits/extc++.h>
// #define oo INT_MAX
#define _rep(i, a, b) for (int i = (a); i <= (b); ++i)
#define _rev(i, a, b) for (int i = (a); i >= (b); --i)
#define _for(i, a, b) for (int i = (a); i < (b); ++i)
#define _rof(i, a, b) for (int i = (a); i > (b); --i)
#define ll long long
#define all(x) x.begin(), x.end()
#define db double
#define eps 0.00001
#define met(a, b) memset(a, b, sizeof(a))
#define lowbit(x) x &(-x)
#define cost first
#define what_is(x) cerr << #x << " is " << x << endl;
#define val second
#define oo INT_MAX
#define pi acos(-1.0)
using namespace std;
const int maxn = 1 << 12;
ll dp[maxn][12];
int n, m;
bool valid[maxn];
int main()
{
    while (cin >> n >> m && n)
    {
        memset(dp, 0, sizeof(dp)), memset(valid, 0, sizeof(valid));
        bool zeros = 0, is_odd = 0;
        _for(i, 0, (1 << m))
        { //筛出所有合法状态
            bool zeros = 0, is_odd = 0;
            _for(j, 0, m)
            {
                if ((i >> j) & 1)
                { //如果是1
                    is_odd |= zeros;
                    if (is_odd)
                        break;
                }
                else
                {
                    zeros ^= 1;
                }
            }
            valid[i] =( is_odd | zeros ? 0:1);
        }
        dp[0][0] = 1;
        _rep(r, 1, n){
            _for(i, 0, (1 << m)){//当前行的状态
                _for(j, 0, (1 << m)){//上一行的状态
                    if(!valid[j | i])continue;
                    if((j & i) != 0)continue;
                    dp[i][r] += dp[j][r - 1];
                }
            }
        }
        cout << dp[0][n] << endl;
    }

}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值