291. 蒙德里安的梦想【状压DP】

求把N*M的棋盘分割成若干个1*2的的长方形,有多少种方案。

例如当N=2,M=4时,共有5种方案。当N=2,M=3时,共有3种方案。

如下图所示:

2411_1.jpg

输入格式

输入包含多组测试用例。

每组测试用例占一行,包含两个整数N和M。

当输入用例N=0,M=0时,表示输入终止,且该用例无需处理。

输出格式

每个测试用例输出一个结果,每个结果占一行。

数据范围

1≤N,M≤111≤N,M≤11

输入样例:

1 2
1 3
1 4
2 2
2 3
2 4
2 11
4 11
0 0

输出样例:

1
0
1
2
3
5
144
51205

题源POJ 2411

参考博客 https://blog.csdn.net/u013480600/article/details/19569291

#include <iostream>
#include <cstdio>       //EOF,NULL
#include <cstring>      //memset
#include <cmath>        //ceil,floor,exp,log(e),log10(10),hypot(sqrt(x^2+y^2)),cbrt(sqrt(x^2+y^2+z^2))
#include <algorithm>    //fill,reverse,next_permutation,__gcd,
#include <string>
#include <vector>
#include <queue>
#include <stack>
#include <map>
using namespace std;
#define rep(i, a, n)		for (int i = a; i < n; ++i)
#define sca(x)			scanf("%d", &x)
#define sca2(x, y)		scanf("%d%d", &x, &y)
#define sca3(x, y, z)		scanf("%d%d%d", &x, &y, &z)
#define pri(x)			printf("%d\n", x)
#define pb	push_back
#define mp	make_pair
typedef pair<int, int>		P;
typedef long long		ll;
const ll inf = 99999999999;
const int INF = 0x3f3f3f3f;
const int mod = 1e9+7;
const int maxn = 105;
const int N = 1e4 + 5;
int t, n, m;
int cnt, ans, ed;
ll dp[15][1<<15];
int path[50000][2];
int h, w;
void dfs(int l, int now, int pre)
{
	if (l > w) {
		return;
	}
	if (l == w) {
		path[cnt][0] = pre;
		path[cnt++][1] = now;
		return;
	}
	dfs(l + 2, (now << 2)|3, (pre << 2)|3); // 竖放,当前行为1,上一行为0
	dfs(l + 1, (now << 1)|1, (pre << 1)); // 横放 当前行和上一行都为11
	dfs(l + 1, (now << 1), (pre << 1)|1);  //不放,上一行为1,当前行为0
}


int main()
{
	while (sca2(h, w) && h && w)
	{
		if (h < w) {
			swap(h, w);
		}
		cnt = 0;
		dfs(0, 0, 0);
		memset(dp, 0, sizeof dp);
		ed = (1 << w) - 1;
		dp[0][ed] = 1;
		for (int i = 0; i < h; i++)
		{
			for (int j = 0; j < cnt; j++)
			{
				dp[i + 1][path[j][1]] += dp[i][path[j][0]];
			}
		}
		printf("%lld\n", dp[h][ed]);
	}
	return (0);
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值