HDU 4804 Campus Design 轮廓线DP
2016-08-05 18:46
417 查看
原题
DescriptionNanjing University of Scienceand Technology is celebrating its 60th anniversary. In order to make room forstudent activities, to make the university a more pleasant place for learning,and to beautify the campus,
the college administrator decided to startconstruction on an open space.
The designers measured the open space and come to a conclusion that the openspace is a rectangle with a length of n meters and a width of m meters. Thenthey split the open space into n x m squares. To make it more beautiful, thedesigner decides to cover the
open space with 1 x 1 bricks and 1 x 2 bricks,according to the following rules:
1. All the bricks can be placed horizontally or vertically
2. The vertexes of the bricks should be placed on integer lattice points
3. The number of 1 x 1 bricks shouldn’t be less than C or more than D. Thenumber of 1 x 2 bricks is unlimited.
4. Some squares have a flowerbed on it, so it should not be covered by anybrick. (We use 0 to represent a square with flowerbet and 1 to represent othersquares)
Now the designers want to know how many ways are there to cover the open space,meeting the above requirements.
Input
There are several test cases,please process till EOF.
Each test case starts with a line containing four integers N(1 <= N <=100), M(1 <= M <= 10), C, D(1 <= C <= D <= 20). Then following Nlines, each being a string with the length of M. The string consists of ‘0’ and‘1’ only, where ‘0’ means the square should
not be covered by any brick, and‘1’ otherwise.
Output
Please print one line per testcase. Each line should contain an integers representing the answer to theproblem (mod 10
9 + 7).
大意
给一个大平面矩形格子,格子标号为0的不防砖,1的放砖,砖有1x1和1x2两种,其中1x1的只能使用C~D个,1x2无限制,输出方案数。思路
这是一道典型的轮廓线动态规划的贴砖块问题。状态上记录轮廓上每个格子的放置情况。这是因为每个放置最多影响到下一行和旁边一个格子,所以只要记录边缘的状态就可以了,记录轮廓而不是每行的状态是为了按格子递推的时候方便处理。没格只记录是否放,用01表示压缩成一个二进制数。如果记录放哪种砖,后面再把1*1的合并,则会出现叠加部分分不清的尴尬局面。
递推的方式采取按一格一格的递推,每一格只修改当前所对应的状态位,如果横放1*2的则修改左边的状态位。虽然每一格后状态所表示的格子不同了,但这并不会让状态相互重叠。因为在每次递推到下一格的时候即滚动数组,状态也就统一到新轮廓下的各种方案数。
这一类动态规划比插头的要简单许多,我觉得可以都归结为轮廓形,插头是轮廓状态记录是否有伸出去。推荐陈丹琦女神的经典论文《基于连通性状态压缩的动态规划问题》。
代码 C
#include <stdio.h> #include <string.h> #define MOD 1000000007 long long dp[2][1024][22]; int main() { int n, m, c, d, i, j, k, s, cur; char squre[12]; while(scanf("%d%d%d%d", &n, &m, &c, &d) > 0) { memset(dp, 0, sizeof dp); dp[cur=0][(1<<m)-1][0] = 1; for(i=0; i<n; i++) { scanf("%s", squre); for(j=0; j<m; j++) { cur ^= 1; memset(dp[cur], 0, sizeof dp[cur]); for(k=1<<m; k--;) for(s=0; s<=d; s++) { if(squre[j] == '1') { if(k & 1 << j) { dp[cur][k][s+1] = (dp[cur][k][s+1] + dp[cur^1][k][s]) % MOD; dp[cur][k^1<<j][s] = (dp[cur][k^1<<j][s] + dp[cur^1][k][s]) % MOD; if(j && !(k&1<<j-1)) dp[cur][k^1<<j-1][s] = (dp[cur][k^1<<j-1][s] + dp[cur^1][k][s]) % MOD; } else dp[cur][k^1<<j][s] = (dp[cur][k^1<<j][s] + dp[cur^1][k][s]) % MOD; } else if (k & 1 << j) { dp[cur][k][s] = (dp[cur][k][s] + dp[cur^1][k][s]) % MOD; } } } } for(i=c, s=0; i<=d; i++) s = (s + dp[cur][(1<<m)-1][i]) % MOD; printf("%d\n", s); } return 0; }
相关文章推荐
- 如何组织构建多文件 C 语言程序(二)
- 如何写好 C main 函数
- 书评:《算法之美( Algorithms to Live By )》
- 动易2006序列号破解算法公布
- C#递归算法之分而治之策略
- Ruby实现的矩阵连乘算法
- C#插入法排序算法实例分析
- C#算法之大牛生小牛的问题高效解决方法
- Lua和C语言的交互详解
- C#算法函数:获取一个字符串中的最大长度的数字
- 超大数据量存储常用数据库分表分库算法总结
- C#数据结构与算法揭秘二
- C#冒泡法排序算法实例分析
- 算法练习之从String.indexOf的模拟实现开始
- C#算法之关于大牛生小牛的问题
- C#实现的算24点游戏算法实例分析
- 经典排序算法之冒泡排序(Bubble sort)代码
- 关于C语言中参数的传值问题
- 简要对比C语言中三个用于退出进程的函数
- 深入C++中API的问题详解