ZOJ 1100 Mondriaan's Dream【状态压缩】【DP】【DFS】

15 篇文章 0 订阅
6 篇文章 0 订阅

题目链接

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]);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值