标签:HDU 1400 覆盖 二进制 位置 一行 矩形 Dream dp
题目链接:HDU 1400 Mondriaan's Dream
题目大意:
用\(1\times 2\)的矩形完全覆盖一个\(n\times m\)矩形区域,求覆盖方案数。
题解:
将某一行用二进制来表示是否被覆盖了,压缩信息到一个整数中,进行状态转移。
设\(dp[i][j]\)表示前\(i\)行,除最后一行其他都完全覆盖,而最后一行在\(j\)的二进制对应位为\(1\)的位置竖着覆盖矩形的上半部分,\(0\)的位置横着覆盖矩形或竖着覆盖矩形的下半部分的情况数。
如果\(j\)的二进制为\(0\),若竖着覆盖,则其上一行的对应位置必须为\(1\);若横着覆盖,则其相邻位置必须也有\(0\),设上一行的状态为\(k\),则须满足\(j|k\)中每段连续的\(0\)的个数为偶数(\(j|k\)之后剩下的\(0\)位均为横着覆盖的矩形位置)且\(j\& k=0\)(若某位是\(1\),则表示其是矩形上半部分,则其上一行的对应位置一定是横着覆盖的矩形或者竖着覆盖的矩形的下半部分,肯定为\(0\),所以按位与之后必定为\(0\))。
状态转移方程为:
\[dp[i][j]=\sum_{j,k符合条件}dp[i-1][k] \]初始\(dp[0][0]=1\),答案为\(dp[n][0]\)。
#include <cstring>
#include <iostream>
using namespace std;
long long dp[12][1 << 11];
int n, m;
bool check(int x, int y) {
if (x & y) {
return false;
}
int t = x | y, cnt = 0;
for (int i = 0; i < m; ++i) {
if (!(t & 1 << i)) {
cnt++;
} else if (cnt & 1) {
return false;
}
}
return !(cnt & 1);
}
int main() {
while (cin >> n >> m && (n || m)) {
if (n & 1 && m & 1) {
cout << 0 << endl;
continue;
}
memset(dp, 0, sizeof(dp));
dp[0][0] = 1;
for (int i = 1; i <= n; ++i) {
for (int j = 0; j <= (1 << m) - 1; ++j) {
for (int k = 0; k <= (1 << m) - 1; ++k) {
if (check(j, k)) {
dp[i][j] += dp[i - 1][k];
}
}
}
}
cout << dp[n][0] << endl;
}
return 0;
}
标签:HDU,1400,覆盖,二进制,位置,一行,矩形,Dream,dp
来源: https://www.cnblogs.com/IzumiSagiri/p/15059671.html
本站声明:
1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。