• 动态规划:铺砖问题


    问题描述:给定n*m的格子,每个格子被染成了黑色或者白色。现在要用1*2的砖块覆盖这些格子,要求块与块之间互相不重叠,且覆盖了所有白色的格子,但不覆盖任意一个黑色格子。求一共有多少种覆盖方法,输出方案数对M取余后的结果。

    限制条件:

    • 1 <= n <= 15
    • 1 <= m <= 15
    • 2 <= M <= 10^9

    样例输入:

    n = 3

    m = 3

    ...(.代表白色,x带表黑色)

    .x.

    ...

    输出:2

    解题思路:

    为了不重复统计,我们每次从最左上方的空格处开始放置。对于哪些格子已经被覆盖过了,只需要用一个bool数组来维护就可以了。首先,黑色的格子不能被覆盖,因此used里对应的位置总是false。对于白色的格子,如果要在(i,j)的位置放置砖块,那么由于总是从最左上方的可放的格子开始放置,因此对于(i',j‘) < (i,j)(按字典序比较)的(i',j')总有used[i'][j'] = true成立。

    此外,由于砖块的大小为1*2,因此对于每一列j'在满足(i',j')<= (i , j)的所有i‘中,除了最小的i’之外,都满足used[i'][j'] = false。因此,不确定的只有每一列里还没有查询的格子中最上面的一个,共m个。从而可以把m个格子通过状态压缩编码进行记忆话搜索。

    代码实例:

    int dp[2][1 << MAX_M];
    void solve() {
    	int *crt = dp[0],*next = dp[1];
    	crt[0] = 1;
    	for(int i = n-1;i >= 0;i--){
    		for(int j = m-1;j >= 0;j--){
    			for(int used = 0;used <1 << m;used ++){
    				if((used >> j &1) || color[i][j]){
    					next[used] = crt[used &~(1<<j)];
    				}else{
    					int res = 0;
    					if(j + 1 > m && !(used >> (j+1) & 1) && !color[i][j+1]){
    						res += crt[used | 1 << (j+1)];
    					}
    					if(i+1 < n && !color[i+1][j]){
    						res += crt[used | 1<<j];
    					}
    					next[used] = res % M;
    				}
    			}
    			swap(crt,next);
    		}
    	}
    	printf("%d
    ",crt[0]);
    }
  • 相关阅读:
    清除浮动解决父元素高度塌陷问题
    canvas画动图
    vue实现列表的循环滚动
    localStorage读写操作
    angularJS快速入门
    python模块
    python函数式编程
    python高级特性
    Flask 快速入门
    JQuery Ajax
  • 原文地址:https://www.cnblogs.com/long98/p/10352222.html
Copyright © 2020-2023  润新知