poj2411状压dp

题目

求把N*M的棋盘分割成若干个1*2的的长方形,有多少种方案。

例如当N=2,M=4时,共有5种方案。当N=2,M=3时,共有3种方案。

如下图所示:

2411_1.jpg

输入格式

输入包含多组测试用例。

每组测试用例占一行,包含两个整数N和M。

当输入用例N=0,M=0时,表示输入终止,且该用例无需处理。

输出格式

每个测试用例输出一个结果,每个结果占一行。

数据范围

1≤N,M≤111≤N,M≤11

输入样例:

1 2
1 3
1 4
2 2
2 3
2 4
2 11
4 11
0 0

输出样例:

1
0
1
2
3
5
144
51205

如果正常看的话很不好看那么就把每个1*2的方块沿着棋盘横向切开把它们变成1*1的所以每一行就分成了2*1的和1*1的这个1*1的有可能是和上一行也有可能是和下一行构成一个方块因此我们把行作为阶段1表示竖着的上部分0表示其他情况可能横可能竖然后就可以通过二进制来表示每一行的状态,然后上一行转移到下一行的条件就是1.上一行和下一行进行按位与运算之后的结果为0(假设上一行的一位是0那么下一行对应的位置是1,0都无所谓因为上一行的横块并不影响下一行,如果是1的话那么下一行必须是0如果下一行也是1的话那么它的竖块就拼不成了),2.上一行和下一行进行或运算的结果他的连续的0的数量必须是偶数(进行或运算之后表示为0的结果上一行的0表示竖着的块的下半块或者是横着的下一行表示是横着的如果是奇数的话就没法分割成这种横着的)。

初始化dp[0][0]=1,表示给他第一行之前给他堵死,终点dp[n][0]是因为第n行没法再存在1了;

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N=13;
long long dp[13][1<<N];
bool f[1<<N];
int m,n;
int main()
{
    while(cin>>n>>m&&n&&m)
    {
        memset(dp,0,sizeof(dp));
       // memset(f,0,sizeof(f));
    for(int i=0;i<(1<<m);i++)
    {
        int ans=0;
        for(int j=0;j<m;j++)
        {
            if(i>>j&1){
                if(ans%2==1)
                    break;
                else
                    ans=0;
            }
            else
                ans++;
        }
        if(ans%2==1)
            f[i]=false;
        else
            f[i]=true;
    }
    dp[0][0]=1;
    int maxx=0;
    for(int i=1;i<=n;i++)
    {
        for(int j=0;j<(1<<m);j++)
        {
            for(int k=0;k<(1<<m);k++)
            {
                if((j&k)==0&&f[j|k])
                    dp[i][j]+=dp[i-1][k];
                //maxx=max(maxx,dp[i][k]);
                //cout<<dp[i][j]<<' ';
            }
        }
        //cout<<endl;
        
    }
    cout<<dp[n][0]<<endl;
    }
    
}

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值