pku 2411 modriaans dream 压缩dp 解题报告

pku 2411 modriaans dream解题报告

很显然利用了状态压缩dp,我们假设:

00ß-------à00 横放

1ß----------à1 竖放

那么以sample2 4为例,得到的答案为一下:

1

0000

0000

2

0000              1100

1100 或者: 0000

3

1111               0000

0000 或者: 1111

4

1001               0000

0000 或者: 1001

5

0011             0000

0000 或者:0011

所以,我们对于状态转移方程需进行三种操作:

1、  往每个格子+1;

2、  往每2个格子+2;

3、  取反操作.

然后我们假设第一行为0,全为0,一层一层dp下去,这样我们就实现了状态压缩dp.

AC代码:

 

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

 

__int64 dp[12][2048];

int n, m;

 

/*

就这两种状态转移:

横着放 00 -> 00

竖着放 0 -> 1

*/

//1表示已经放了,不能放了,0表示还能放.

void dfs(int i, int Initial, int Target, int s)

{

       //Initial是初始状态,jj是目标状态

    if (s == m)

       {

              dp[i + 1][Target] += dp[i][Initial];

       //     printf("i(%d) j(%d) (i+1)%d (jj)%d/n", i, Initial, i+1, Target);

       }

    else if ((Target & (1 << s)) == 0)        

    {

        dfs(i, Initial, Target | (1 << s), s + 1);              

        if (s < m - 1 && (Target & (1 << (s + 1))) == 0)  

              {

                     dfs(i, Initial, Target, s + 2);

              }

    }

    else

       {

             dfs(i, Initial, Target & ~(1 << s), s + 1);   //~表示按位取反运算符

       }

}

/*

经典的状态压缩DP.f[i][j]表示第i,方格排布为二进制数j(k位上为1表示凸出一个格子,0表示不凸出)的方案数.

DFS进行状态转移.

*/

int main()

{

       freopen("1.txt", "r", stdin);

       int i, j;

 

    while (scanf("%d%d", &n, &m), n + m != 0)

    {

        memset(dp, 0, sizeof(dp));

        dp[0][0] = 1;

        for (i = 0; i < n; i++)

              {

                     for (j = 0; j < (1 << m); j++)   //共有1<<m种情况可以考虑

            {

                            if (dp[i][j])

                {

                                   dfs(i, j, j, 0);

                            }

                     }

              }

              printf("%I64d/n", dp[n][0]);

    }

    return 0;

}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值