码迷,mamicode.com
首页 > 其他好文 > 详细

UVA 11270 Tiling Dominoes

时间:2020-02-11 14:41:38      阅读:56      评论:0      收藏:0      [点我收藏+]

标签:并且   ogr   css   string   qml   psd   bmc   ash   acl   

https://vjudge.net/problem/UVA-11270

题目

用$1\times2$骨牌覆盖$n\times m$棋盘,有多少种方法?

$n\times m<101$

题解

棋盘已经填了的部分只能用考虑轮廓线表示清楚,不能只用行和列。轮廓线总共有$2^{宽}$种状态,因此需要把宽度尽量缩小。

令$n\leqslant m$,可以得到$n\leqslant 10$,所以轮廓线的状态有$2^{10}$种。

只在轮廓线的右下角放骨牌,并且保证轮廓线的上面是完全填满了的。比如下图这样的情况

技术图片

每次轮廓线都会往右前进一格,那么就需要保证轮廓线第一位在前进后变成1

规定只允许对轮廓线进行修改,那么就有三种情况

  • 不放
  • 往左放
  • 往上放

其中不放和往左放都要求第一位是1,往左放还要求最后一位是0且当前位置不是第一列。

往上放要求第一位是0

轮廓线的位置有$m\times n$种,状态有$2^{n}$种,其中位置可以滚动优化掉。

初始状态是$dp[0][(1<<n)-1]=1$,而dp[0]的其他状态因为都含0,导致在后面的某个时刻无法继续转移(第一排,不能往上放,也不能往左或不放),所以虽然会被用到,最后一定会被抛弃。

ac代码

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<cctype>
#include<cassert>
#define REP(i,a,b) for(register int i=(a); i<(b); i++)
#define REPE(i,a,b) for(register int i=(a); i<=(b); i++)
using namespace std;
typedef long long ll;
int n,m;
int msk, hi;
ll dp[2][1<<10];
int main() {
	while(~scanf("%d%d", &n, &m)) {
		if(n>m) swap(n,m);
		msk = (1<<n)-1, hi=1<<(n-1);
		dp[0][msk]=1;
		int now = 0;
		REP(i,0,m) REP(j,0,n) {
			now^=1; memset(dp[now],0,sizeof(dp[now]));
			REPE(k,0,msk) {
				if(k&1) dp[now][k>>1]+=dp[now^1][k];
				if(i && !(k&1)) dp[now][(k>>1)|hi]+=dp[now^1][k];
				if(j && (k&1) && !(k&hi)) dp[now][((k|hi)>>1)|hi]+=dp[now^1][k];
			}
		}
		printf("%lld\n", dp[now][msk]);
	}
}

 

UVA 11270 Tiling Dominoes

标签:并且   ogr   css   string   qml   psd   bmc   ash   acl   

原文地址:https://www.cnblogs.com/sahdsg/p/12294908.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!