hdu 1992 Tiling a Grid With Dominoes

31 篇文章 0 订阅
5 篇文章 0 订阅

Notes

2018.1.30:这篇博客关于轮廓线的理解有误,请看这篇:hdu 4804 Campus Design

Problem

acm.hdu.edu.cn/showproblem.php?pid=1992

Reference

blog.csdn.net/csuhoward/article/details/45308865

blog.csdn.net/bossup/article/details/21948079

wenku.baidu.com/view/ce445e4f767f5acfa1c7cd51.html

Meaning

4 * w 的路要用 1 * 2 的砖铺满,问方案数。

Analysis

据说是轮廓线DP。

约定:称题中定长的一维为高。现考虑从左到右一列列地铺,对每一列都从上到下地一行行考虑铺法。

因为砖是 1 * 2 的,所以每一列的铺法只受左边一列影响,也只能影响右边那列。

对当前考虑的列,用一串 0/1 来标记每一个格是否有铺砖。0表示当前格未铺砖,1表示已铺(左边那列等高的一行打横铺了一块,顺便把这格也铺了)。


定义状态:dp[c][S]:第 c 列铺成 S 这个样子的方案数。

如果从前面的状态来算当前状态有点麻烦,于是用当前状态来推后面的状态。对于当前列,从上到下考虑,如果这一格已经被铺了,就直接跳到下一列;否则,考虑打横放还是打竖放。打横放是肯定可行的;打竖放要考虑是否够放、下面一格是否已经铺了砖。同时用另一个变量表示当前列的右边一列,在考虑当前列的铺法时,维护一下右边的一列被影响成怎么样(有哪些格被当前列打横的砖铺过去了),记为 next_S。(参考博客里说的0表示不占右边那列、1表示占,大概是 next_S 中没有被占、被占,最后答案是dp[n][0],我的解释又好像说不通了…玄学)

则在当前列的所有格都考虑完之后,状态转移:dp[c+1][next_S] += dp[c][S]

感觉就是从当前列的一个合法的轮廓出发,考虑所有的铺法,铺完之后就形成一个新的合法轮廓,然后把方案数加上去。

Source code

#include <cstdio>
#include <cstring>
using namespace std;
const int H = 4, W = 30;

int dp[W][1<<H];

void dfs(int r, int c, int now, int nxt)
{
	if(r == H) // 已经铺完所有行
		dp[c+1][nxt] += dp[c][now];
	else if(now >> r & 1) // 这一格已经被铺
		dfs(r+1, c, now, nxt);
	else
	{
		dfs(r+1, c, now, nxt|1<<r); // 打横铺砖,顺便占了右边那格
		if(r+1 < H && !(now >> (r+1) & 1)) // 考虑能不能打竖铺
			dfs(r+2, c, now, nxt);
	}
}

int main()
{
	memset(dp, 0, sizeof dp);
	dp[0][0] = 1;
	for(int i=0; i<W; ++i)
		for(int j=0; j<1<<H; ++j)
			if(dp[i][j]) // 如果当前轮廓合法(可以铺成这样)
				dfs(0, i, j, 0);
	int t;
	scanf("%d", &t);
	for(int n, kase=1; kase<=t; ++kase)
	{
		scanf("%d", &n);
		printf("%d %d\n", kase, dp[n][0]);
	}
	return 0;
}
后来想想应该是这样:因为数组的下标从0开始,dp[n][0]就应该是表示第 n+1 列的轮廓是 0000(也就是什么都没铺),而第 n 列是铺满的。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值