poj2411(状压dp)

 

题目链接:http://poj.org/problem?id=2411

题意:由1*2 的矩形通过组合拼成大矩形,求拼成指定的大矩形有几种拼法。

分析:如果是横着的就定义11,如果竖着的定义为竖着的01,状态兼容时只需考虑两种情况,当前行|上一行,是不是全为1,不是说明竖着有空(不能出现竖着的00),然后再当前行&上一行,这里被消掉的1全部用来竖着放的,判断之后的状态是否有奇数的连续1,有则不能转移的,因为剩下的都是用来行着放了。

 

#include <cstdio>

#include <cstring>

#include <string>

#include <cmath>

#include <iostream>

#include <algorithm>

#include <queue>

#include <cstdlib>

#include <stack>

#include <vector>

#include <set>

#include <map>

#define LL long long

#define mod 100000000

#define inf 0x3f3f3f3f

#define eps 1e-9

#define N 100010

#define FILL(a,b) (memset(a,b,sizeof(a)))

#define lson l,m,rt<<1

#define rson m+1,r,rt<<1|1

using namespace std;

LL dp[15][1<<12];

int fit[1<<12];

int tot,n,m;

bool ok(int x)//判断一行状态中是否有奇数的连续1

{

    int opp=0;

    while(x)

    {

        if(x&1)opp++;

        else

        {

            if(opp&1)return 0;

            opp=0;

        }

        x>>=1;

    }

    return (opp&1)==0;

}

bool judge(int j,int k)

{

    if((j|k)!=(1<<m)-1)return false;

    return fit[j&k];

}

int main()

{

    for(int i=0;i<(1<<11);i++)if(ok(i))fit[i]=1;

    while(scanf("%d%d",&n,&m)>0)

    {

        if(n+m==0)break;

        FILL(dp,0);

        if(m*n&1)

        {

            puts("0");continue;

        }

        if(n<m)swap(n,m);

        for(int i=0;i<(1<<m);i++)

        dp[1][i]=fit[i];

        for(int i=2;i<=n;i++)

        {

            for(int j=0;j<(1<<m);j++)

                for(int k=0;k<(1<<m);k++)

                if(judge(j,k))

                dp[i][j]+=dp[i-1][k];

        }

        printf("%lld\n",dp[n][(1<<m)-1]);

    }

}
View Code

 

你可能感兴趣的:(poj)