HDU 1400 Mondriaan's Dream(状压DP)

来源:互联网 发布:linux查看所有文件夹 编辑:程序博客网 时间:2024/06/05 05:11

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1400


题意:问1*2的砖块拼成h*w的矩形有多少种拼法。

思路:dp[i][j]表示第i行的状态为j时的方法数。如果这个点有砖则为1,没有则为0。注意:时限为10s。因此我们可以枚举行数,枚举i行状态以及i-1行状态,复杂度O(h * 2^w * 2^w)。


#include <iostream>#include <stdio.h>#include <cmath>#include <algorithm>#include <iomanip>#include <cstdlib>#include <string.h>#include <vector>#include <queue>#include <stack>#include <ctype.h>using namespace std;int temp[3005][20];void init(){    memset(temp,0,sizeof(temp));    for(int i=0;i<=3000;i++)    {        int x=i;        int cnt=0;        while(x>0)        {            temp[i][cnt]=x%2;            x/=2;            cnt++;        }    }}int n,m;long long dp[20][3005];bool isok(int j,int k){    if(m==1)   特判m=1的情况    {        if(temp[k][0]==0&&temp[j][0]==0) return false;        if(temp[k][0]==1&&temp[j][0]==1) return false;        return true;    }    for(int l=0;l<m;l++)    {        if(temp[j][l]==1&&temp[k][l]==1)        {            if(temp[j][l+1]==1&&temp[k][l+1]==1)   //如果横着摆了1*2的砖,直接跳过l+1的判断            {                l++;                continue;            }            else return false;   //如果当前只摆了1*1的砖是不合法的        }        if(temp[k][l]==0&&temp[j][l]==0) return false;    //如果上一行第l格为空,这一行必须摆竖着的,否则不合法    }    return true;}int main(){    init();    while(scanf("%d%d",&n,&m)!=EOF)    {        if(n==0 && m==0) break;        memset(dp,0,sizeof(dp));        int sum=1<<m;        dp[0][sum-1]=1;        for(int i=1;i<=n;i++)        {            for(int j=0;j<sum;j++)   //第i行的状态            {                for(int k=0;k<sum;k++)     //第i-1行的状态                {                    if(isok(j,k))                    {                        dp[i][j]+=dp[i-1][k];                    }                }            }        }        cout<<dp[n][(1<<m)-1]<<endl;    }    return 0;}


0 0
原创粉丝点击