状压DP_ POJ 2411

解释

开始看不出这是一个状压DP的问题,但是看到其他博客中每种摆放的状态表示的时候,终于想通了这个问题的解法:

状态表示:横着放置:全部为1,竖着放置:上面为0、下面为1

那么我们就可以用二进制表示出所有的状态了,并且当前行的状态只和上一行状态相关,现在就找一下每种状态之间的限制

1、i-1行为0的相应位置,在i行中必须全部为 1  (因为为0的状态一定为竖着放置,那么他的下面必须为1)

2、i-1行和i行中相应位置同为1的段长度必须为偶数 (因为除去竖着放置的,那么i与i-1行上下必须全部为1,并且这样横着放置的每个都有两个1,那么这样的状态就一定为偶数个)

3、第一行我们只需要判断连续为1的段长为偶数即可,因为没有上面一行竖着放置的限制

dp[i][j] 表示: 第i行状态为j时满足的数量

并且我们不管怎么样最后一行第一定的,最后一行必须全部为1,因为不会再次出现下面一行的信息,也就是不会从最后一行生成一个新的竖放置的,所以我们最终的答案就一定是:dp[n][(1<<m)-1]

程序

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include<string.h>
#include<algorithm>
#include<math.h>
#include<queue>
using namespace std;
typedef long long ll;
const int N = 12;
ll dp[N][1<<N];//
int n,m;

bool Judge(int x)//判断是否所有连续1的个数都为偶数
{
    int num = 0;
    while(x)
    {
        if(x & 1) num ++;
        else
        {
            if(num & 1) return false;
            num = 0;
        }
        x >>= 1;
    }
    if(num & 1) return false;
    return true;
}

int main()
{
    while(scanf("%d%d",&n,&m) && n+m)
    {
        memset(dp,0,sizeof(dp));
        for(int i = 0;i < (1<<m);i ++)
            if(Judge(i))  //限制3
                dp[1][i] = 1;
        for(int i = 1;i < n;i ++)
            for(int j = 0;j < (1<<m);j ++)
                if(dp[i][j])
                {
                    for(int k = 0;k < (1<<m);k ++)
                        if((j | k) == (1<<m)-1 && Judge(j & k))//依次放置限制1、2的发生
                            dp[i+1][k] += dp[i][j];
                }
        printf("%I64d\n",dp[n][(1<<m)-1]);
    }
    return 0;
}

参考

http://www.cnblogs.com/kuangbin/archive/2013/04/28/3049684.html


猜你喜欢

转载自blog.csdn.net/li1615882553/article/details/80186063
今日推荐