您的位置:首页 > 其它

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]+=pre
pre表示母状态的种数。

一开始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