1.如何界定是否不可达
对于一个矩形,能够从左下角走到右上角的路径,一定是在
左边界
+上边界
和 右边界
+ 下边界
这两个极端路径之间的(如图中红蓝
两个线路)。
那么不可达
的意思就是:在极端边界的两种情况上,各有一个点
,并且这两个点之间存在一条“拦截线
”(紫色)。这样从左下角到右上角的所有通路都无法抵达。
所以,如果圆组合而形成的路线中存在满足上述条件的一个拦截线,那么就不可达。
对于一组圆来说,需要满足以下三个条件使之不可达:
-
某一个圆和左侧 或者 上侧 边界
有交点
(至少相切) -
某一个圆和右侧 或者 下侧 边界
有交点
(至少相切) -
有一个由 其余圆 组成的“组合图形”链接这两个圆 并且 在这个“组合图形”中
每两个相交的圆
必须存在相交的部分是“严格
”在矩形内
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外部的循环,如果圆满足:
包含
左下角 或者 右上角;
或者
- 和左侧 或 上侧 边界
有交点
,并且可以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内部,我们执行:
-
取出一个圆,判断是否已经和 右侧 或者 下侧 边界有交点。
-
如果是,返回
True
,退出dfs; -
如果不是,标记圆为以访问,然后遍历
全部没有访问过的圆
,如果每一个圆和其构成的相交区
有一个点严格在矩形内
并且 其往下搜索的结果返回了True,那么我们返回True -
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