算法笔记:带障碍的铺砖问题

问题描述:给定一个长方形地面,地面上有石头,现在要用长度为1x2的砖去铺满没有障碍的区域,砖可以横着或者竖着,但不能切割。最简单的例子,比如地面大小是2x2,没有障碍,那就用两块1x2的砖即可铺满。而假如是3x3的地面,正好中心点有一个障碍,剩下四个方向各放一块砖也能铺满。那么当地面很大的时候呢?

这道题一开始想了很久,一直想用带有回溯的方式去搜索所有可能性。但非常复杂,水平有限没写出来。后来想到了一个01染色的方法,用两种颜色去染空白区域,比如黑白,一黑一白即为一块砖,并且同样颜色的砖块不能相邻。也就是说白色四周(上下左右)只能是黑,反之亦然。

看下面几个例子,画图的时候黑色区域表示障碍,0和1分别是两种颜色。这个题肯定是不能根据空白区域的大小来判断的,下面两个图,空白区域都是6,但是右边这个你怎么都没办法用完整的砖块铺满。

在这里插入图片描述
在这里插入图片描述
当染色结束后,只需要统计01两种颜色的个数是否想等即可。

然而仅仅统计01个数是否相等就能判断了吗,答案肯定是不能的。如下图,当空白区域被障碍分割时,该方法会出现问题

在这里插入图片描述
但可以发现,不连通的也是可以判断的,只需要分开判断即可(如上图),虽然总数相等,但每个区域内部01是不等的。

这种分开判断的思想参考了《leetcode 200 岛屿数量》这道题的部分思想。即我的搜索算法执行次数 等于 分开的空白区域 的个数。

并且这种朝四个方向染色的思想,跟岛屿数量那道题也挺像。

代码实现:

import numpy as np
dx=[1,0,0,-1]
dy=[0,1,-1,0]
# down, right,left, up
total1=0 
total2=0 
P=np.array(
  [[1,0,0,0,0,1,1,0],
   [1,1,1,1,1,1,0,0],
   [0,0,0,0,1,0,0,0],
   [1,0,0,1,1,0,1,0]] )*2

N = len(P)
M = len(P[0])
st = (P==2) #visited
st_sum = (P==2).sum()
def paint(i, j, k):
    global total1
    global total2
    global st_sum
    if i<0 or i>=N or j<0 or j>=M or P[i][j]==2 or st[i][j]==True: 
        return    
    P[i][j]=k
    st[i][j]=True
    st_sum+=1
    if P[i][j]==0:
        total1+=1
        paint(i+1, j, 1)
        paint(i-1, j, 1)
        paint(i, j+1, 1)
        paint(i, j-1, 1)
    else:
        total2+=1
        paint(i+1, j, 0)
        paint(i-1, j, 0)
        paint(i, j+1, 0)
        paint(i, j-1, 0)
res=True
for i in range(N):
    for j in range(M):
        if st[i][j]==False:
            paint(i, j, P[i][j])
            sub = (total1==total2)
            print("current space: ", sub)
            res = res and sub
            total1=0
            total2=0
            if st_sum==N*M:
                break        
print(P)
print("final result: ", res)

代码解释:

我把所有的障碍标记成2,这样就可以和0,1区分开了,并且每次访问过的位置标记为True,这样就不会重复搜索。st_num用来记录访问的个数,所有障碍都是默认为访问过,当st_num等于矩阵大小时,即可直接结束。

total1和total2分别是记录0和1的个数,当for 循环中的当前paint()执行完之后,比较0和1的个数是否想等,然后和当前结果取和运算,最后重置记数器为0,为下一次的空白区域做准备。

当前代码的测试结果如下:
在这里插入图片描述

可以看到正好三处空间,执行了三次判断,并且都为True。同时还打印了最后染色结束后的矩阵P。

该方法跳过了考虑砖块到底是如何摆放的。只要0和1个数相等,他们可以自动配对。

时间复杂度:
DFS算法,最多遍历NM个位置。复杂度O(NM)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值