dp专辑F - Mondriaan's Dream [状态压缩]

题意:

求一个 n*m 的矩形用 1*2 的矩形进行覆盖的方法总数

分析:

状态压缩

dp[r][k]表示第r行的 凸出状态为k(竖着) 时,前r行最多的方案数,结果就是dp[row-1][0](row从0开始)

//AC CODE:

#include<iostream>
#include<cmath>
#include<algorithm>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<map>
using namespace std;

int cnt, stk[150];
//dp[r][k]表示第r行的 凸出状态为k(竖着) 时,前r行最多的方案数,结果就是dp[row-1][0](row从0开始)
__int64 dp[15][2050];

int get_bit(int num, int index)//取num中的index位
{
    return (num>>(index))&1;
}

bool ok(int n, int x)//检查x是否合法,是否连续出现奇数个0
{
    int count=0;
    for(int i=0; i<n; i++)
    {
        if(get_bit(x,i)==0)
            count++;//x中的第i位是0
        else
        {
            if(count%2!=0)
                return 0;
            count=0;
        }
    }
    if(count%2!=0)//没写这两句话,悲剧了很久。。。
        return 0;//
    return 1;
}

void findStk(int n)//1表示竖着放,0表示横着放,0需要成对出现
{
    for(int i = 0; i < (1<<n); i ++)
        if(ok(n, i))//检查i是否合法
            stk[cnt ++] = i;
}

int main()
{
    int row, col, r, i, k;
    while(scanf("%d %d",&row,&col)!=EOF&&(row||col))
    {
        if((row*col%2)==1)
        {
            printf("0\n");
            continue;
        }
        memset(dp, 0, sizeof(dp));
        cnt = 0;
        findStk(col);
        //第一行
        for(i = 0; i < cnt; i ++)
            dp[0][stk[i]] = 1;//stk[i]竖着的状态
        //其它行
        for(r = 1; r < row; r ++)
            for(i = 0; i < cnt; i ++)
            {
                for(k = 0; k < (1<<col); k ++)
                {
                    if((stk[i] & k) != k)//该行(stk[i])可以添加到上一行(k)的下面
                        continue;
                    dp[r][stk[i]^k] += dp[r-1][k];//stk[i]^k为凸出状态 异或:相同取0,相异取1
                }
            }
        printf("%I64d\n", dp[row-1][0]);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值