1 条题解
-
0
题目分析
我们需要在给定的二进制矩阵中找到最大的圆形区域,使得:
- 圆盘完全在平面内
- 圆盘覆盖的所有点对应的矩阵位置都是 1
- 圆心坐标为整数
- 半径平方取整后最大
核心思路
1. 问题转化
对于每个可能的圆心
(x, y),我们需要找到最大的半径 r,使得以(x, y)为圆心、半径为 r 的圆盘完全位于 1 的区域中。由于圆心坐标是整数,我们可以将问题转化为:对于每个可能的圆心,找到它到最近的 0 的距离。
2. 关键观察
- 圆的半径平方必须是整数(因为圆心和障碍点都是整数坐标)
- 我们需要找到每个点到最近障碍物的距离,然后取最大值
- 障碍物是矩阵中为 0 的位置
3. 算法设计
3.1 预处理垂直距离
代码中定义了:
up[i][j]:从位置(i, j)向上最近的障碍物行号dwn[i][j]:从位置(i, j)向下最近的障碍物行号
这样对于每一列,我们可以快速知道任意行到垂直方向最近障碍物的距离。
3.2 凸包优化
对于每一行 y,我们考虑该行上所有点
(x, y)到障碍物的距离。问题转化为:对于每个 x,找到最小的(x - x₀)² + (y - y₀)²,其中(x₀, y₀)是障碍物。使用凸包技巧(类似于斜率优化)来高效计算:
- 维护一个下凸包
- 对于每个 x,在凸包上二分找到最优的 x₀
- 时间复杂度从 O(M²) 降为 O(M)
3.3 对称处理
代码分别处理原矩阵和翻转后的矩阵:
ans[0]:原矩阵的结果ans[1]:水平翻转后的结果
这样可以同时考虑左右两个方向的障碍物。
4. 具体实现
4.1 距离计算
int dist(int x, int y, int xx, int yy) { return sqr(x - xx) + sqr(y - yy); }4.2 凸包维护
while (tail < head && slope(dq[tail + 1], dq[tail]) >= slope(dq[tail], i)) tail++; dq[--tail] = i;4.3 最终选择
在所有可能的圆心中:
- 优先选择半径平方最大的
- 半径相同时选择 y 坐标最小的
- y 坐标相同时选择 x 坐标最小的
复杂度分析
- 预处理垂直距离:O(N × M)
- 每行的凸包计算:O(M)
- 总复杂度:O(N × M)
- 空间复杂度:O(N × M)
对于 N, M ≤ 3000 完全可行。
样例验证
样例 1
输入: 5 6 011110 111110 011111 111111 011110 输出: 3 2 4解释:以 (3, 2) 为圆心,半径平方为 4 的圆是最大的可行圆。
样例 2
输入: 3 3 010 101 010 输出: 0 0 0解释:没有半径为正整数的圆。
算法标签
- 凸包优化 (Convex Hull Optimization)
- 最近障碍物距离 (Nearest Obstacle Distance)
- 几何处理 (Geometric Processing)
- 动态规划 (Dynamic Programming)
总结
本题通过巧妙的预处理和凸包优化,将看似复杂的几何问题转化为高效的可计算问题。核心在于利用矩阵的特性和凸包的性质,在 O(N × M) 时间内找到最优解。
- 1
信息
- ID
- 5515
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者