【poj2411】Mondriaan's Dream 状压dp

又是一道状压dp入门经典题!dp[i][j]表示第i行的状态为j时的状态数。1表示放个竖着的。首先预处理判断与0的个数,因为只有偶数的时候才能放横着的,转移的时候只要与之前状态逻辑与一下为0并且逻辑或一下的状态有偶数个0(逻辑与一下是因为之前状态竖着的)就是符合条件的,目标是dp[n][0]。

记得开long long

#include<iostream>
#include<cstdio>
#include<cstring>
#define ll unsigned long long
using namespace std;
ll dp[15][1<<15];
int f[1<<15];
int n,m;
int main() {
	for (;(~scanf("%d%d",&n,&m))&&n;) {
		memset(f,0,sizeof(f));memset(dp,0,sizeof(dp));
		for (int i=0;i<1<<m;i++) {
			int cur=0;
			for (int j=0;j<m;j++) {
				if (i&(1<<j)) f[i]|=cur,cur=0;
				else cur^=1;
			}
			f[i]=(f[i]|cur)^1;
		}
		dp[0][0]=1;
		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][k]+=dp[i-1][j];
		printf("%lld\n",dp[n][0]);
	}
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值