题意 : 给定矩形的长宽, 要求用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][r−1]
attention: 可以预处理出每个合法的状态,
双倍经验: 注意枚举的边界
#include <bits/stdc++.h>
#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)
{
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
;
}
}
转载请注明原文地址: https://win8.8miu.com/read-7266.html