SGU 131-状压dp

规模比较小,所以用状态压缩DP来搞,是POJ2411加强版。有以下几种铺法:


##     #.     ##    ##     #.     .#
..       #.     #.      . #     ##   ##
1      2      3        4          5    6

还有一种情况就是不放~~~
我们依然是枚举出合法的当前行以及上一行,不过这里要比POJ2411稍微麻烦点,因为1,3,4,5,6这五种情况当前列的放置会影响后面一列的放置,

所以我们还需要用两个变量来记录是否对下一行有影响,然后就是根据这两个变量的情况进行相应的砖块放置。

例5中有两种DFS方案,其中第二种实现起来较第一种简单。但在本题中,新增的L形骨牌让第二种DFS难以实现,在例5中看起来有些笨拙的第一种DFS方案在本题却可以派上用场。回顾第一种DFS,我们有5个参数,分别为:p(当前列号),s1、s2(当前行和对应的上一行的覆盖情况),b1、b2(上一列的放置对当前列两行的影响,影响为1否则为0)。本题中,可选择的方案增多,故列表给出:


 
容易看出,在本题中此种DFS方式实现很简单。考虑其复杂度,因为L形骨牌不太规则,笔者没能找到一维的方案数的递推公式,因此无法给出复杂度的解析式。但当m=9时,算法共生成放置方案79248个,则对于n=m=9,算法的复杂度为O(9*79248),可以瞬间出解。和上例一样,本题也没有必要保存所有放置方案,也避免MLE。

由于CSDN最近不能粘贴链接,很抱歉,这是周伟的状态压缩论文里面讲的。

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define MAXN 10
typedef long long LL;
LL dp[MAXN][1<<MAXN];
int n,m;
void dfs(int step,int s1,int s2,int u1,int u2,int line)
{
    if(step==m)
    {
        if(!u1&&!u2) dp[line][s2]+=dp[line-1][s1];
        return;
    }
    if(!u2)
    {
        if(!u1)
        {
            dfs(step+1,s1<<1,s2<<1|1,0,0,line);
            dfs(step+1,s1<<1,s2<<1|1,1,0,line);
            dfs(step+1,s1<<1,s2<<1|1,0,1,line);
        }
        dfs(step+1,(s1<<1|1)-u1,s2<<1|1,0,1,line);
        dfs(step+1,(s1<<1|1)-u1,s2<<1|1,1,1,line);
    }
    if(!u1)dfs(step+1,s1<<1,s2<<1|u2,1,1,line);
    dfs(step+1,(s1<<1|1)-u1,s2<<1|u2,0,0,line);
}
int main ()
{
    while(scanf("%d%d",&n,&m)!=EOF)
    {

        memset(dp,0,sizeof(dp));
        dp[0][(1<<m)-1]=1;
        for(int i=1; i<=n; i++)
            dfs(0,0,0,0,0,i);
        printf("%I64d\n",dp[n][(1<<m)-1]);
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值