POJ 2411 解题报告
来源:互联网 发布:c语言define怎么用 编辑:程序博客网 时间:2024/06/07 20:53
这道题是状态压缩DP。之前应该做过一次类似的,但这道题比较难些。花了比较久理解状态压缩DP。周伟的论文《状态压缩》是最好的资料。
这道题是论文中的一道例题。论文中提到,由于合法状态特别多,所以这里对每一行都跑一次DFS,而不是提前保存下来。这样可以节省空间,时间上也没多少影响。事实也确实如此,16ms就过了。
整体过程是从上到下一行行往下填,DP[r][s]表示,第r行状态为s时填充方法有多少。我们要求的是DP[h - 1][(1 << w) - 1]的值,因为我们需要保证最后一行全都填充。
我们可以讲横着(horizontal)放置的小方块表示为11。即当前行的当前列和下一列填1。而把竖着(vertical)放置的小方块表示为01。即上一行的当前列为0,当前行的当前列为1。最后一行全都填充的意思是最后一行的每一列都不能是竖条的起点(0),即必须全为1,所以我们有(1<<w) - 1。
当前行的状态只和前一行的状态有关,反过来讲,如果当前行的状态确定,上一行的状态也确定了。反过来想比较容易填充 DP[r][s]。
对每一行,我们从左到右一列列填充。具体来说,
1.如果我们在当前行r的列c和c+1放一个横条,那么上一行(r -1)的c和c +1也必须为1(一个横条或者两个竖条的终点,或者一半一半,总之必须为11)。即有:
dfs(r, c + 2, (s1 << 2) | 3, (s2 << 2) | 3);
2.如果我们将当前行r的列c作为竖条的终点,那么上一行(r -1)的当前列c一定是竖条的起点(0)。即有:
dfs(r, c + 1, (s1 << 1) | 1 , s2 << 1);
3.如果我们将当前行r的列c作为竖条的起点,那么上一行(r -1)的当前列c一定是已经填充好了,即必须为1(无论是横条还是竖条的终点,总之已经“完整”地填充了)。即有:
dfs(r, c + 1, s1 << 1 , (s2 << 1) | 1);
当前行的状态s1是所有上一行可能的状态s2的填充方法之和,即:dp[r][s1] += dp[r - 1][s2];
还有一个值得注意的地方是第一行(r = 0)。第一行不能作为竖条的终点,即不能存在上述情况2.并且,因为不存在前一行,dp[r][s1] = 1就好了,即标记本身是合法的就好。
thestoryofsnow2411Accepted308K16MSC++1901B/* ID: thestor1 LANG: C++ TASK: poj2411 */#include <iostream>#include <fstream>#include <cmath>#include <cstdio>#include <cstring>#include <limits>#include <string>#include <vector>#include <list>#include <set>#include <map>#include <queue>#include <stack>#include <algorithm>#include <cassert>using namespace std;const int MAXH = 11;const int MAXW = 11;const int MAXS = 1 << MAXW;int h, w;long long dp[MAXH][MAXS];// horizontal: 1 1// vertical : 0 1// the last row should be all 1// s1 is current row status, // s2 is previous(!!!) row status// according to Zhou Wei's paper, // the valid status is plenty// so we run it every row to save spacevoid dfs(int r, int c, int s1, int s2){if (c >= w){// does not cross borderif (c == w){if (r == 0){dp[r][s1] = 1;}else{dp[r][s1] += dp[r - 1][s2];}}return;}// if current row is horizontal, then the previous row should be horizontal as well// (or both columns are the end of vertical which are the same, '11')dfs(r, c + 2, (s1 << 2) | 3, (s2 << 2) | 3);// current row is the end of vertical, then the previous row should be the start// the first row cannot be the end of verticalif (r != 0){dfs(r, c + 1, (s1 << 1) | 1 , s2 << 1);}// current row is the start of vertical, // then the previous row should be the end// (or part of horizontal, in both cases, '1')dfs(r, c + 1, s1 << 1 , (s2 << 1) | 1);}int main(){while (scanf("%d%d", &h, &w) > 0 && h){// rotate the rectangle to make the width smallerif (h < w){int t = h;h = w;w = t;}for (int r = 0; r < h; ++r){for (int s = 0; s < (1 << w); ++s){dp[r][s] = 0;}}for (int r = 0; r < h; ++r){dfs(r, 0, 0, 0);}// the last row should be all 1printf("%lld\n", dp[h - 1][(1 << w) - 1]);}return 0;}
- POJ 2411 解题报告
- POJ 2411 Mondriaan's Dream 解题报告
- poj数百篇解题报告
- poj 1141解题报告
- poj 1001解题报告
- poj 1011 解题报告
- poj 1087 解题报告
- poj 2153解题报告
- poj 2051解题报告
- POJ 1167 解题报告
- poj 1026 解题报告
- POJ 1077 解题报告
- POJ 1042 解题报告
- POJ 1095 解题报告
- POJ 1159解题报告
- poj 2312解题报告
- POJ 1001解题报告
- POJ 1002解题报告
- BUILD问题“Class not found : Lorg/apache/commons/logging/Log”
- TLD(Tracking-Learning-Detection)学习与源码理解之(学习器)
- bzoj-2300 防线修建
- 网页时钟
- 《Python基础教程 (第2版 修订版)》 第2章 列表和元组(学习笔记· 一)
- POJ 2411 解题报告
- VLAN间通信之端到端模式
- VRF间的重分布
- 我来,然后,不去
- Cocos2d-x 3.0 触摸机制
- 我爱你,祖国
- 核心CISCO7609故障处理
- 静态路由
- leetcode 231 Power of Two(难易度:Easy)