📌  相关文章
📜  Angular Sweep(可以包含在给定半径的圆中的最大点数)

📅  最后修改于: 2021-10-23 08:03:42             🧑  作者: Mango

给定二维平面上的“n”个点,找出半径为“R”的固定半径圆可以包围的最大点数。
注意:即使该点位于圆周上,该点也被视为在圆内。
例子:

Input : R = 1
        points[] = {(6.47634, 7.69628), (5.16828 4.79915), 
                    (6.69533 6.20378)}
Output :  2
The maximum number of points are 2

Input :  R = 1
  points[] = {(6.65128, 5.47490), (6.42743, 6.26189)
   (6.35864, 4.61611), (6.59020 4.54228), (4.43967 5.70059)
   (4.38226, 5.70536), (5.50755 6.18163), (7.41971 6.13668)
   (6.71936, 3.04496), (5.61832, 4.23857), (5.99424, 4.29328)
   (5.60961, 4.32998), (6.82242, 5.79683), (5.44693, 3.82724) 
   (6.70906, 3.65736), (7.89087, 5.68000), (6.23300, 4.59530)
   (5.92401, 4.92329), (6.24168, 3.81389), (6.22671, 3.62210)}
Output : 11
The maximum number of points are 11

朴素算法

  1. 对于给定集合中的任意一对点(比如 A 和 B),构造半径为“R”的圆,同时接触这两个点。最多有 2 个这样的可能的圆圈。正如我们在这里看到的,最大可能的圆圈是针对案例 1,即 2。

半径为“R”的圆接触点 A 和 B

  1. 对于每个构建的圆,检查集合中的每个点是否位于圆内。
  2. 返回包含最大点数的圆。

时间复杂度:有n C 2对点对应,我们最多可以有 2 n C 2圆。对于每个圆,必须检查 (n-2) 个点。这使得朴素算法 O(n 3 )。角度扫描算法
通过使用 Angular Sweep,我们可以在 O(n 2 log n) 内解决这个问题。该算法的基本逻辑思想描述如下。
我们从给定的集合中选择一个任意点 P。然后,我们围绕点 P 旋转一个固定半径“R”的圆。在整个旋转过程中,P 位于圆的圆周上,我们将圆中点的数量保持在给定的 Θ 值,其中参数 Θ 确定旋转角度。由于半径是固定的,因此圆的状态可以由单个参数 Θ 确定。
我们还可以看到,只有当集合中的一个点进入或退出圆时,保持的计数值才会改变。

单个参数 Θ 控制圆的方向

在给定的图中,C1 是 Θ = 0 的圆,C2 是我们以 Θ 的一般值旋转圆时构建的圆。
之后,问题就归结为,如何维护count的值。
对于除 P 之外的任何给定点(比如 Q),我们可以轻松计算出它进入圆的 Θ 值(设为 α)和退出圆的 Θ 值(设为 β)。
我们有角度 A 和 B 定义如下,

  • A 是 PQ 和 X 轴之间的角度。
  • B 是 PC 和 PQ 之间的角度,其中 C 是圆心。

A = tan^{-1}  \frac{(P.y - Q.y)}{(P.x-Q.x)} \\\\ B = cos^{-1}  \frac{d}{2R}

其中,x 和 y 表示点的坐标,“d”是 P 和 Q 之间的距离。
现在,从图表中我们可以看出,

α = A-B 
β = A+B

(注意:所有角度都相对于 X 轴。因此,它变成了“AB”而不是“BA”)。
当 Q 进入圆圈时

当 Q 退出圆圈时

我们可以计算除 P 之外的所有点的角度 A 和 B。一旦找到这些角度,我们对它们进行排序,然后按递增顺序遍历它们。现在我们维护一个计数器,它告诉我们在特定时刻圆内有多少点。
只有当一个点进入或退出圆时,计数才会改变。如果我们找到一个进入角,我们将计数器加 1,如果我们找到一个退出角,我们将计数器减 1。检查角度是进入还是退出可以使用标志轻松实现。
像这样继续,计数器总是为我们提供特定状态下圆内点数的有效值。
重要提示: ‘d’>2R 的点不必考虑,因为 永远不会进入或退出圆。
角度扫描算法可以描述为:

  1. 计算每对n C 2点之间的距离并存储它们。
  2. 对于任意点(例如 P),使用 getPointsInside()函数获取可以位于围绕 P 旋转的圆内的最大点数。
  3. 返回的所有值中的最大值将是最终答案。

此算法已在以下 C++ 实现中进行了描述。

CPP
// C++ program to find the maximum number of
// points that can be enclosed by a fixed-radius
// circle
#include 
using namespace std;
 
const int MAX_POINTS = 500;
 
// complex class which is available in STL has
// been used to implement points. This helps to
// ensure greater functionality easily
typedef complex Point;
 
Point arr[MAX_POINTS];
double dis[MAX_POINTS][MAX_POINTS];
 
// This function returns the maximum points that
// can lie inside the circle of radius 'r' being
// rotated about point 'i'
bool mycompare(pair A, pair B)
{
    if(A.firstB.first)
        return false;
    else
        return (A.second==1);
}
int getPointsInside(int i, double r, int n)
{
    // This vector stores alpha and beta and flag
    // is marked true for alpha and false for beta
    vector > angles;
 
    for (int j=0; j >::iterator it;
    for (it=angles.begin(); it!=angles.end(); ++it)
    {
        // entry angle
        if ((*it).second)
            count++;
 
        // exit angle
        else
            count--;
 
        if (count > res)
            res = count;
    }
 
    return res;
}
 
// Returns count of maximum points that can lie
// in a circle of radius r.
int maxPoints(Point arr[], int n, int r)
{
    // dis array stores the distance between every
    // pair of points
    for (int i=0; i


输出 :

The maximum number of points are: 2

如果您希望与专家一起参加现场课程,请参阅DSA 现场工作专业课程学生竞争性编程现场课程