sgu 131解题记录

7 篇文章 0 订阅

131. Hardwood floor

time limit per test: 0.25 sec. 
memory limit per test: 4096 KB

The banquet hall of Computer Scientists' Palace has a rectangular form of the size M x N (1<=M<=9, 1<=N<=9). It is necessary to lay hardwood floors in the hall. There are wood pieces of two forms:
1) rectangles (2x1) 
2) corners (squares 2x2 without one 1x1 square) 
You have to determine X - the number of ways to cover the banquet hall. 
Remarks. The number of pieces is large enough. It is not allowed to leave empty places, or to cover any part of a surface twice, or to saw pieces.

Input

The first line contains natural number M. The second line contains a natural number N.

Output

First line should contain the number X, or 0 if there are no solutions.

Sample Input

2 3

Sample Output

5
题目链接:http://acm.sgu.ru/problem.php?contest=0&problem=131

题目大意:

      你有个N*M的矩阵,和如下两种方块 1---1*2的方块. 2---2*2缺一个角的方块. 要求铺满整个矩阵,且无相交.输出方案数。

解题记录:

        第一想法——状态压缩DP

                很典型的一道状态压缩DP,但是是3年前OI做过几道,只记得大致构架。

                阶段:每层为一个阶段;

                状态:该层每个格子是否被砖块覆盖(1表示覆盖0表示没有覆盖);

                转移:大概有6个转移方法:1*2砖块有2种摆放,2*2缺一个的角的有4种摆放。

                然后就列出了状态转移方程:

                        f[i][j] = f[i][j']+1;  f[i][j]= f[i-1][j']+1; 这是6种不同的摆法来转移

                        f[i][j] = f[i][j'];  某个格子不进行摆放,留给后面的状态来进行填充

          越想越纠结,似乎这样就即没无后效性,也没有充分利用子问题,只能看看题解了(=_=#,最近看题解频率略高啊)

                看来对动态规划基本概念还是没有理解:

                       阶段即为每个子问题,每个阶段的决策组成一个决策序列即为整个决策。状态转移应当是在阶段与阶段之间,而不是阶段内部。

                       这样看来,之前我列出来的状态转移方程,似乎就是一个搜索而不是状态转移。

                       那么正确的状态转移应当是: f[i][j] = f[i-1][j']+cnt; 其中cnt为i-1层的j'转移到i层的j需要的砖块个数,这样也保证了无后效性。

解题报告:

1. 题目要求我们用2种不同的方块铺满 N*M的矩形区域的总方案数,此题如果用裸搜则会超时,裸搜的话会造成许多的冗余信息没有很好的利用。例如:

         N*M矩形区域,已经用裸搜铺到第K层,且前K层已经全部铺满即一个K*M的矩形,则后面的N-K层与前面的K层无关。当后面的N-K层的方案数已经搜索完毕时,下次再遇到N-K层的情况,则需要再搜索一次,此时我们就没有利用好之前的信息。

2. 我们可以考虑用一下动态规划的思想,动态规划需要满足2个条件:1. 最优子结构; 2. 无后效性。然而判断是否符合,则需要先构建出一个动态规划模型,然后再进行判断。

        首先,先确定问题决策的对象,根据题目描述,我们的决策对象可设为满足N*M矩形区域的方案数。然后,对该决策进行阶段划分并确定状态量,使得每个阶段之间有联系,且符合最优子结构与无后效性两个条件。

        我们尝试按照每个格子进行阶段划分,如若以每个格子为独立阶段,则无法确立一种子结构顺序,使得满足最优子结构这一条件。例如4*3矩形区域中,格子(2,2)无法找到一种阶段顺序,使得当递推到格子(2,2)时,确保之前的方案都是满足最优性质的。

         从第一个想法中,我们可以拓展出,如若以层数为阶段划分,以每层被覆盖的情况为状态,每层的状态可用一个2进制数字来表示,每个阶段的当前状态即为最优答案(最大方案数)且为子结构。前一个阶段状态并不受后一个阶段状态的影响,满足无后效性。

         至此满足动态规划的2个条件,则可以进行建立状态转移方程: f[i][s] = ∑ (f[i-1][s'] + cnt)  i为阶段(即为第几层), s与s'均为状态,只不过一个属于第i阶段,一个属于第i-1阶段,cnt则是s'转移到s所需要的方块数,可通过深搜获得。由于只与前面的1个阶段有关,可以用滚动数组。

代码:

#include <cstdio>
#include <cstring>
#define bin(i) (1<<i)
#define emp(a, i) (!(a&bin(i)))

using namespace std;

int n, m, full;
long long f[1<<10], g[1<<10];

void init() {
	scanf("%d%d", &m, &n);
	full = (1<<m)-1;
	f[full] = 1;
}

void dfs(int a, int b, long long cnt) {
	if (a == full) {
		g[b] += cnt;
		return;
	}

	for (int i = 0; i < m; i++)
		if (emp(a,i)) {
			if (i+1 < m && emp(a, i+1)) {
				dfs(a|bin(i)|bin(i+1), b, cnt);
				if (emp(b, i))  dfs(a|bin(i)|bin(i+1), b|bin(i), cnt);
				if (emp(b, i+1))  dfs(a|bin(i)|bin(i+1), b|bin(i+1), cnt);
			}
			if (emp(b,i)) {
				dfs(a|bin(i), b|bin(i), cnt);
				if (i+1 < m && emp(b, i+1)) dfs(a|bin(i), b|bin(i)|bin(i+1), cnt);
				if (i >= 1 && emp(b, i-1)) dfs(a|bin(i), b|bin(i-1)|bin(i), cnt);
			}

			break;
		}
}

void solve() {
	for (int k = 1; k <= n+1; k++) {
		for (int i = 0; i <= full; i++)
			if (f[i])  dfs(i, 0, f[i]);
	
		memcpy(f, g, sizeof(g));
		memset(g, 0, sizeof(g));
	}

	printf("%lld\n", f[0]);
}

int main() {
	init();
	solve();
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值