首页 > 学院 > 开发设计 > 正文

hdu 1992 Tiling a Grid With Dominoes

2019-11-06 07:25:47
字体:
来源:转载
供稿:网友

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 列是铺满的。


发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表