ZOJ 1100 Mondriaan's Dream【状态压缩】【DP】【DFS】
2016-03-21 20:50
459 查看
题目链接
http://www.icpc.moe/onlinejudge/showProblem.do?problemId=100思路
题意很简单,给你个h*w的格子,让你用2*1的长方形去填满它,问有几种填法。题意简单不代表好写啊,这TM怎么搞。。。比赛时想破脑子也只能想个暴力出来,妥妥TLE。
后来搜了下题解终于做出来了,是状压DP+dfs。这是我第二次碰到搜索和状压组合的题目了,但状压+DP+搜索这么复杂的还是第一次。
设
dp[state][i]表示把第i行摆成sate状态的方法种数,state是个w位的二进制数,1表示这一格已经被某个长方形遮住了,0表示空的。
然后对每行仅考虑横着放和竖着向上放,竖着向下放不考虑,因为完全可以用下一行的竖着向上方等价代替。
每拿到一行,先对其取反,得出下一行的初始状态。因为上一行为0的位置下一行一定要用竖块给填上。
例如:1011001
取反:0100110,0表示还能放的位置。
然后dfs枚举这一行所有可能的状态,然后
dp[state][i]+=prepre表示母状态的种数。
一开始pre=1,把第一行枚举下。
最后答案就是
dp[111111(w个1)][h]。
还有个小坑就是取反的时候记得把前导零清零,不然就乱套了。
AC代码
#include <iostream> #include <iomanip> #include <fstream> #include <sstream> #include <cmath> #include <cstdio> #include <cstring> #include <cctype> #include <algorithm> #include <functional> #include <numeric> #include <string> #include <set> #include <map> #include <stack> #include <vector> #include <queue> #include <deque> #include <list> using namespace std; typedef long long ll; ll dp[1<<11][12]; int h,w; ll pre; void dfs(int r,size_t s,int cur) { if(cur>=w-1) { dp[s][r]+=pre; return; } dfs(r,s,cur+1); if((s&(1<<cur))==0 && cur<w-1 && (s&1<<(cur+1))==0 ) dfs(r,(s|(1<<cur)|(1<<cur+1)),cur+2); } int main() { while(scanf("%d%d",&h,&w),h) { memset(dp,0,sizeof dp); if((h&1) && (w&1)) { printf("0\n"); continue; } pre=1; dfs(0,0,0); for(int r=0 ; r<h-1 ; ++r) { for(size_t s=0 ; s<(1<<w) ; ++s) { pre=dp[s][r]; if(pre==0) continue; dfs(r+1,~s&((1<<w)-1),0); } } printf("%lld\n",dp[(1<<w)-1][h-1]); } }
相关文章推荐
- 简单的四则运算
- 数的奇偶性
- ACM网址
- 1272 小希的迷宫
- 1272 小希的迷宫
- hdu 1250 大数相加并用数组储存
- 矩阵的乘法操作
- 蚂蚁爬行问题
- 蚂蚁爬行问题
- 求两个数的最大公约数【ACM基础题】
- 打印出二进制中所有1的位置
- 杭电题目---一只小蜜蜂
- HDOJ 1002 A + B Problem II (Big Numbers Addition)
- 初学ACM - 半数集(Half Set)问题 NOJ 1010 / FOJ 1207
- 初学ACM - 组合数学基础题目PKU 1833
- POJ ACM 1002
- POJ 2635 The Embarrassed Cryptographe
- POJ 3292 Semi-prime H-numbers
- POJ 2773 HAPPY 2006
- POJ 3090 Visible Lattice Points