You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

求过原点且与所有圆相交的最少直线数的O(n.log(n))贪心算法

嘿,这个几何转贪心的问题我刚好有思路,咱们一步步来拆解!

问题转化:从几何到区间覆盖

首先得把“过原点的直线与圆相交”这个几何条件,转化成更容易处理的数学模型:
对于每个圆 ( c_i(x_i,y_i,r_i) ),计算原点到圆心的距离 ( d_i = \sqrt{x_i^2 + y_i^2} ):

  • 如果 ( d_i \leq r_i ):原点在圆内(或圆上),任何过原点的直线都会和这个圆相交,直接把这类圆从待处理集合里剔除就行
  • 如果 ( d_i > r_i ):过原点的直线和圆相交的充要条件是,圆心到直线的距离 ≤ ( r_i )。把直线用方向角 ( \theta ) 表示(从x轴正方向逆时针转的角度,范围统一为 ( [0, 2\pi) )),这个条件可以转化为:( \theta ) 必须落在区间 ( [\phi_i - \alpha_i, \phi_i + \alpha_i] ) 内,其中
    • ( \phi_i = \text{arctan2}(y_i, x_i) )(圆心的极角)
    • ( \alpha_i = \arcsin(r_i/d_i) )(直线允许的角度偏移量)

这里要注意:如果计算出的区间跨了 ( 2\pi )(比如 ( [3\pi/2, \pi/2] )),需要把它拆成两个不跨周期的区间:( [3\pi/2, 2\pi) ) 和 ( [0, \pi/2] ),同时把所有区间复制一份并加上 ( 2\pi )(用来处理跨周期的覆盖逻辑)。

到这里,问题就完全变成了经典的区间点覆盖问题:用最少的点(每个点对应一条直线的角度 ( \theta ))覆盖所有上述区间。而这个问题的最优贪心算法刚好满足 ( O(n\log n) ) 的时间复杂度!

贪心算法设计(最优且符合复杂度要求)

这个贪心策略的核心逻辑是:每次选能覆盖最多未覆盖区间的点,数学上已经证明,选择当前未覆盖区间中右端点最小的那个区间的右端点,就能得到最优解。具体步骤如下:

  1. 预处理所有圆:
    • 对每个圆计算 ( d_i ),剔除 ( d_i \leq r_i ) 的圆
    • 对剩下的圆计算对应的角度区间,处理跨周期的区间并拆分,同时复制所有区间并加上 ( 2\pi )
  2. 排序区间:
    • 把所有有效区间按右端点从小到大排序,这一步的时间复杂度是 ( O(n\log n) ),也是整个算法的时间瓶颈
  3. 贪心选择直线:
    • 初始化直线数量 ( count = 0 ),当前覆盖的最右端角度 ( current_end = -1 )(表示初始未覆盖)
    • 遍历排序后的每个区间:
      • 如果当前区间的左端点 > ( current_end ) 且 ( current_end < 2\pi ):说明这个区间还没被覆盖,需要新增一条直线,角度选这个区间的右端点,同时更新 ( current_end ) 为这个右端点,( count += 1 )
关于你提到的“构造3条直线”的补充

你说的遍历每个圆构造3条直线,可能是想尝试圆的切线或者其他关键角度?其实本质上,最优解里的每条直线对应的角度,一定是某个区间的右端点(也就是某个圆的过原点的切线角度,每个圆最多两条切线),所以不需要构造额外的第三条直线。把问题转化为区间覆盖后,用上面的贪心策略就能直接得到最少直线数,而且是严格最优的。

内容的提问来源于stack exchange,提问作者BolbazarMarme

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 06:44:58