POJ 2411 Mondriaan’s Dream
Posted in PKU OJ on 四月 8th, 2010 by 纳米 – Be the first to comment2009-12-02,AC
解题报告:
这是一道状态压缩DP。首先对每一行设计状态,对于某个位置,有空和非空两种情况。什么情况下进行状态转移呢?
(1) (x, y)为空,(x-1, y)不为空,表示该(x, y)为一个竖着的方块的上面一格;
(2) (x, y)不为空,(x-1, y)为空,表示该(x, y)为一个竖着的方块的下面一格;
(3) (x, y)、(x-1, y)均不为空,并且一行中有一段连续的、数量为偶数的这样的格子,表示这一段连续的格子为横着的方块。
我们用0表示空,1表示非空,每行不超过11个格子,于是我们可以进行二进制编码。为了提高速度,可以预先处理某个状态A可以从哪些状态转移而来。
还有一个优化,就是h*w为奇数答案显然为0。
当然,可以打表-.-
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 | #include <stdio.h> #include <string.h> const int pow[] = {1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048}; const int maxn = 11, maxpow = 2049; int n, m; int match[maxpow][maxpow], size[maxpow] = {0}; long long dp[2][maxpow]; bool check1(int x, int y) { int c = 0; for (int i = 0; i < m; ++i) { if (!(x & 1) && !(y & 1)) return false; if (x & 1 ^ y & 1 && c & 1) return false; if (x & 1 && y & 1) ++c; x >>= 1; y >>= 1; } if (c & 1) return false; else return true; } bool check2(int x) { int c = 0; while (x > 0) { if (x & 1) ++c; else if (c & 1) return false; x >>= 1; } return !(c & 1); } int init() { memset(size, 0, sizeof(size)); for (int i = 0; i < pow[m]; ++i) for (int j = 0; j < pow[m]; ++j) if (check1(i, j)) match[i][size[i]++] = j; return 0; } long long work() { int pm = pow[m]; memset(dp[1], 0, sizeof(dp[1])); for (int i = 0; i < pm; ++i) if (check2(i)) dp[1][i] = 1; for (int i = 2; i <= n; ++i) { int now = i & 1; int pre = 1 - now; memset(dp[now], 0, sizeof(dp[now])); for (int j = 0; j < pm; ++j) for (int k = 0; k < size[j]; ++k) dp[now][j] += dp[pre][match[j][k]]; } int now = n & 1; int pre = 1 - now, pm1 = pm - 1; dp[now][pm1] = 0; for (int k = 0; k < size[pm1]; ++k) dp[now][pm1] += dp[pre][match[pm1][k]]; return dp[n & 1][pm - 1]; } int main() { while (1) { scanf("%d%d", &n, &m); if (n == 0 || m == 0) break; if (n * m & 1) { printf("0\n"); } else { if (n < m) { int t = n; n = m; m = t; } init(); printf("%I64d\n", work()); } } return 0; } |