每日一题|3235.判断矩形的两个角落是否可达|几何关系、深度优先搜索


在这里插入图片描述

1.如何界定是否不可达

对于一个矩形,能够从左下角走到右上角的路径,一定是在

左边界+上边界右边界 + 下边界

这两个极端路径之间的(如图中红蓝两个线路)。
在这里插入图片描述

那么不可达的意思就是:在极端边界的两种情况上,各有一个点,并且这两个点之间存在一条“拦截线”(紫色)。这样从左下角到右上角的所有通路都无法抵达。

所以,如果圆组合而形成的路线中存在满足上述条件的一个拦截线,那么就不可达。

对于一组圆来说,需要满足以下三个条件使之不可达:

  1. 某一个圆和左侧 或者 上侧 边界有交点(至少相切)

  2. 某一个圆和右侧 或者 下侧 边界有交点(至少相切)

  3. 有一个由 其余圆 组成的“组合图形”链接这两个圆 并且 在这个“组合图形”中每两个相交的圆必须存在相交的部分是“严格”在矩形内

2.如何计算每一个位置关系

这里可以参考Leetcode给出的位置关系总结。一共是4种:

在这里插入图片描述

1、点在圆内(圆内 也包含 圆上)

        # 判断点是否在圆内
        def in_circle(ox, oy, r, x, y):
            return (x - ox) ** 2 + (y - oy) ** 2 - r ** 2 <= 0

2、圆和 左侧 或者 上侧 边界相交

        # 判断点A是否严格在矩形内
        def in_rec(x1, y1, r1, x2, y2, r2):
            return (x1 - x2) ** 2 + (y1 - y2) ** 2 <= (r1 + r2) ** 2 and\
                x1 * r2 + x2 * r1 < (r1 + r2) * xCorner and \
                y1 * r2 + y2 * r1 < (r1 + r2) * yCorner

3、圆和 右侧 或者 下侧 边界相交

        # 判断圆是否与矩形左边 or 上边相交
        def in_left_or_up(x, y, r):
            return (x <= xCorner and abs(y - yCorner) <= r) or \
                            (y <= yCorner and x <= r) or \
                            (y > yCorner and in_circle(x, y, r, 0, yCorner))

4、圆和圆相交 并且 相交部分的一个点“严格”在矩形内部

        # 判断圆与矩形的右 or 下边界相交
        def in_right_or_down(x, y, r):
            return (y <= yCorner and abs(x - xCorner) <= r) or \
                    (x <= xCorner and y <= r) or \
                    (x > xCorner and in_circle(x, y, r, xCorner, 0))

3.如何设计搜索流程

我们维护一个全局0-1数组来记录圆是否被搜索到过

对于dfs外部的循环,如果圆满足:

  1. 包含 左下角 或者 右上角;

或者

  1. 和左侧 或 上侧 边界有交点,并且可以dfs一路到右侧 或者 下侧边界。

返回False

        for i, (x, y, r) in enumerate(circles):
            """
            左上角 or 右下角 在圆内 or
            圆和矩形左上边界相交 and 一直连接到右下边界
            """
            if in_circle(x, y, r, 0, 0) or \
                in_circle(x, y, r, xCorner, yCorner) or \
                (not vis[i] and in_left_or_up(x, y, r) and \
                dfs(i)):
                return False

对于dfs内部,我们执行:

  1. 取出一个圆,判断是否已经和 右侧 或者 下侧 边界有交点。

  2. 如果是,返回True,退出dfs;

  3. 如果不是,标记圆为以访问,然后遍历全部没有访问过的圆,如果每一个圆和其构成的相交区有一个点严格在矩形内 并且 其往下搜索的结果返回了True,那么我们返回True

  4. dfs执行完毕没有True返回,则返回False

        def dfs(i):
            x1, y1, r1 = circles[i]

            if in_right_or_down(x1, y1, r1):
                return True
            
            vis[i] = True

            for j, (x2, y2, r2) in enumerate(circles):
                """
                当前圆没遍历 and 
                连接线上的一点严格在矩形内 and 
                从此开始dfs返回的结果中有True(也就是抵达了右上or右下边界)
                """
                if not vis[j] and in_rec(x1, y1, r1, x2, y2, r2) and dfs(j):
                    return True

            return False

完整的代码如下:

class Solution:
    def canReachCorner(self, xCorner: int, yCorner: int, circles: List[List[int]]) -> bool:
        # 判断点是否在圆内
        def in_circle(ox, oy, r, x, y):
            return (x - ox) ** 2 + (y - oy) ** 2 - r ** 2 <= 0

        # 判断点A是否严格在矩形内
        def in_rec(x1, y1, r1, x2, y2, r2):
            return (x1 - x2) ** 2 + (y1 - y2) ** 2 <= (r1 + r2) ** 2 and\
                x1 * r2 + x2 * r1 < (r1 + r2) * xCorner and \
                y1 * r2 + y2 * r1 < (r1 + r2) * yCorner

        # 判断圆是否与矩形左边 or 上边相交
        def in_left_or_up(x, y, r):
            return (x <= xCorner and abs(y - yCorner) <= r) or \
                            (y <= yCorner and x <= r) or \
                            (y > yCorner and in_circle(x, y, r, 0, yCorner))

        # 判断圆与矩形的右 or 下边界相交
        def in_right_or_down(x, y, r):
            return (y <= yCorner and abs(x - xCorner) <= r) or \
                    (x <= xCorner and y <= r) or \
                    (x > xCorner and in_circle(x, y, r, xCorner, 0))

        vis = [False] * len(circles)

        def dfs(i):
            x1, y1, r1 = circles[i]

            if in_right_or_down(x1, y1, r1):
                return True
            
            vis[i] = True

            for j, (x2, y2, r2) in enumerate(circles):
                """
                当前圆没遍历 and 
                连接线上的一点严格在矩形内 and 
                从此开始dfs返回的结果中有True(也就是抵达了右上or右下边界)
                """
                if not vis[j] and in_rec(x1, y1, r1, x2, y2, r2) and dfs(j):
                    return True

            return False

        for i, (x, y, r) in enumerate(circles):
            """
            左上角 or 右下角 在圆内 or
            圆和矩形左上边界相交 and 一直连接到右下边界
            """
            if in_circle(x, y, r, 0, 0) or \
                in_circle(x, y, r, xCorner, yCorner) or \
                (not vis[i] and in_left_or_up(x, y, r) and \
                dfs(i)):
                return False
        
        return True
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值