您的位置:首页 > 其它

HDU 1400 Mondriaan's Dream(状压DP)

2016-08-13 12:36 405 查看
题目链接: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
[(1<<m)-1]<<endl;
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: