CSP 201409-5 拼图问题
一、题目信息
第一次写博客,有什么疏漏之处,欢迎各位大佬指出<(* ̄▽ ̄*)/-
题目要求
试题编号 | 201409-5 |
---|---|
试题名称 | 拼图 |
时间限制 | 3.0s |
试题名称 | 256.0MB |
-
题目描述
给出一个n×m的方格图,现在要用如下L型的积木拼到这个图中,使得方格图正好被拼满,请问总共有多少种拼法。其中,方格图的每一个方格正好能放积木中的一块。积木可以任意旋转。 给出一个n×m的方格图,现在要用如下L型的积木拼到这个图中,使得方格图正好被拼满,请问总共有多少种拼法。其中,方格图的每一个方格正好能放积木中的一块。积木可以任意旋转。输入格式
输入的第一行包含两个整数n, m,表示方格图的大小。
输出格式
输出一行,表示可以放的方案数,由于方案数可能很多,所以请输出方案数除以1,000,000,007的余数。
样例输入
6 2
样例输出
4
样例说明
四种拼法如下图所示:
评测用例规模与约定
在评测时将使用10个评测用例对你的程序进行评测。
评测用例1和2满足:1<=n<=30,m=2。
评测用例3和4满足:1<=n, m<=6。
评测用例5满足:1<=n<=100,1<=m<=6。
评测用例6和7满足:1<=n<=1000,1<=m<=6。
评测用例8、9和10满足:1<=n<=10^15,1<=m<=7
二、题目分析
一般读完题目,可能第一反应试试暴力搜索,但从题目的位置(这是最后一道题)和给定的数据量级来看,是不可能用暴力搜索搜索解决该问题的,因为该题目中的方格图行数 row<=1015,每行共有的可能情况为2m次方,所以方格图的总状态数目为 (2m)n(n为行数,m为列数),这是一个非常恐怖的数字,当n比较大时,即使交给“神威太湖之光”来计算,也不可能是计算的出来。因此,还是老老实实解题吧(* ̄︶ ̄)~
但在在做之前要考虑以下极为重要的两点问题:
- 用什么数据结构表示方格图(或者说每个格子)的状态?
- 如此量级的数值取值范围,如何提高效率?
做过此类题目的人应该比较敏感,其实这就是动态规划中经典的状态压缩模型。
- 状态表示
在这里用一个二进制数表示每一行格子的状态,如(1010_0000)2,表示一行格子中第1,3个格子被填充,其余空白,如图:在这里用一个二进制数表示每一行格子的状态,如(1010_0000)2,表示一行格子中第1,3个格子被填充,其余空白,如图:
所以,如果这是第i行,这里这一行的状态可以表示为d[i]=160,但是这里有n行,难道真的要用长度为n的数组保存状态,当然不是,既然是动态规划,必然是分析出该题目中对应的状态转移方程,用来表示放置积木的导致的状态转移过程。 - 状态转移矩阵
其实很容易发现,为什么题目中只给出了一个"L"型的积木(可以加上高度为2的“I”型积木),而没有给高度为4的“I”型和高度为3的“L”型的积木(PS:我说的这些积木是什么样子,就不给出图片了, 相信玩过俄罗斯方块的都知道),是因为高度 <=2 ,上一行的放置操作只会影响到下一行的格子状态,而不会对下下行产生任何直接影响,因此很方便我们使用矩阵表示状态转移,因而,此处我们用一个二维数组status[][]表示状态转移矩阵,(划重点)status[i][j]表示的是在当前行初始状态为i(转换成二进制)的情况下,将当前行放满并且下一行最终状态为j(转换为二进制)的方案数(划重点)。例如status[0][105](105二进制表示:01101001)表示下边的状态