DP(状压专题二)

it2022-05-05  176

题意 : 给定矩形的长宽, 要求用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)