先决条件:给定圆上的三个点时的圆方程,凸包
给定一个数组arr [] [] ,该数组在二维平面中包含N个具有整数坐标的点。任务是找到最小封闭圆(MEC)的中心和半径。最小封闭圆是所有点都位于圆内或其边界上的圆。
例子:
Input: arr[][] = {{0, 0}, {0, 1}, {1, 0}}
Output: Center = {0.5, 0.5}, Radius = 0.7071
Explanation:
On plotting the above circle with radius 0.707 and center (0.5, 0.5), it can be observed clearly that all the mentioned points lie either inside or on the circle.
Input: arr[][] = {{5, -2}, {-3, -2}, {-2, 5}, {1, 6}, {0, 2}}
Output: Center = {1.0, 1.0}, Radius = 5.000
幼稚的方法:可以通过一些观察来解决此问题。
- 可以进行的第一个观察是,MEC与至少一个点相交。这是因为,如果MEC在任何点都不相交,则圆可能会进一步缩小,直到它在其中一个点相交为止。
- 可以得出的第二个观察结果是,给定一个圆包围所有点并在单个点处相交,则可以通过将中心移向该点同时将点保持在圆边界上,直到圆与一个点相交,从而进一步缩小圆或更多额外积分。
- 如果圆在两个点(A和B)处相交并且距离AB等于圆直径,则该圆将不再收缩。否则,圆的中心可以朝AB的中点移动,直到圆与第三个点相交(圆不再收缩)。
从以上观察结果可以得出结论,MEC可以:
- 与2点A和B相交,其中AB =圆直径。对于这种情况,圆的中心将是A和B的中点,半径将是距离AB的一半。
- 相交3个或更多点。本文已讨论了找到中心和半径的方法。
因此,对于N <= 3,此问题的解决方案是微不足道的。对于其他情况,可以形成一个简单的想法来解决此问题。想法是使用所有成对的和三重的点来获得定义这些点的圆。获得圆后,测试以查看其他点是否被该圆包围,并返回找到的最小有效圆。
下面是上述方法的实现:
CPP
// C++ program to find the minimum enclosing
// circle for N integer points in a 2-D plane
#include
#include
#include
using namespace std;
// Defining infinity
const double INF = 1e18;
// Structure to represent a 2D point
struct Point {
double X, Y;
};
// Structure to represent a 2D circle
struct Circle {
Point C;
double R;
};
// Function to return the euclidean distance
// between two points
double dist(const Point& a, const Point& b)
{
return sqrt(pow(a.X - b.X, 2) + pow(a.Y - b.Y, 2));
}
// Function to check whether a point lies inside
// or on the boundaries of the circle
bool is_inside(const Circle& c, const Point& p)
{
return dist(c.C, p) <= c.R;
}
// The following two functions are the functions used
// To find the equation of the circle when three
// points are given.
// Helper method to get a circle defined by 3 points
Point get_circle_center(double bx, double by,
double cx, double cy)
{
double B = bx * bx + by * by;
double C = cx * cx + cy * cy;
double D = bx * cy - by * cx;
return { (cy * B - by * C) / (2 * D),
(bx * C - cx * B) / (2 * D) };
}
// Function to return a unique circle that intersects
// three points
Circle circle_from(const Point& A, const Point& B,
const Point& C)
{
Point I = get_circle_center(B.X - A.X, B.Y - A.Y,
C.X - A.X, C.Y - A.Y);
I.X += A.X;
I.Y += A.Y;
return { I, dist(I, A) };
}
// Function to return the smallest circle
// that intersects 2 points
Circle circle_from(const Point& A, const Point& B)
{
// Set the center to be the midpoint of A and B
Point C = { (A.X + B.X) / 2.0, (A.Y + B.Y) / 2.0 };
// Set the radius to be half the distance AB
return { C, dist(A, B) / 2.0 };
}
// Function to check whether a circle encloses the given points
bool is_valid_circle(const Circle& c, const vector& P)
{
// Iterating through all the points to check
// whether the points lie inside the circle or not
for (const Point& p : P)
if (!is_inside(c, p))
return false;
return true;
}
// Function to return find the minimum enclosing
// circle from the given set of points
Circle minimum_enclosing_circle(const vector& P)
{
// To find the number of points
int n = (int)P.size();
if (n == 0)
return { { 0, 0 }, 0 };
if (n == 1)
return { P[0], 0 };
// Set initial MEC to have infinity radius
Circle mec = { { 0, 0 }, INF };
// Go over all pair of points
for (int i = 0; i < n; i++) {
for (int j = i + 1; j < n; j++) {
// Get the smallest circle that
// intersects P[i] and P[j]
Circle tmp = circle_from(P[i], P[j]);
// Update MEC if tmp encloses all points
// and has a smaller radius
if (tmp.R < mec.R && is_valid_circle(tmp, P))
mec = tmp;
}
}
// Go over all triples of points
for (int i = 0; i < n; i++) {
for (int j = i + 1; j < n; j++) {
for (int k = j + 1; k < n; k++) {
// Get the circle that intersects P[i], P[j], P[k]
Circle tmp = circle_from(P[i], P[j], P[k]);
// Update MEC if tmp encloses all points
// and has smaller radius
if (tmp.R < mec.R && is_valid_circle(tmp, P))
mec = tmp;
}
}
}
return mec;
}
// Driver code
int main()
{
Circle mec = minimum_enclosing_circle({ { 0, 0 },
{ 0, 1 },
{ 1, 0 } });
cout << "Center = { " << mec.C.X << ", " << mec.C.Y
<< " } Radius = " << mec.R << endl;
Circle mec2 = minimum_enclosing_circle({ { 5, -2 },
{ -3, -2 },
{ -2, 5 },
{ 1, 6 },
{ 0, 2 } });
cout << "Center = { " << mec2.C.X << ", " << mec2.C.Y
<< " } Radius = " << mec2.R << endl;
return 0;
}
Python3
# Python3 program to find the minimum enclosing
# circle for N integer points in a 2-D plane
from math import sqrt
# Defining infinity
INF = 10**18
# Function to return the euclidean distance
# between two points
def dist(a, b):
return sqrt(pow(a[0] - b[0], 2) + pow(a[1] - b[1], 2))
# Function to check whether a point lies inside
# or on the boundaries of the circle
def is_inside(c, p):
return dist(c[0], p) <= c[1]
# The following two functions are the functions used
# To find the equation of the circle when three
# points are given.
# Helper method to get a circle defined by 3 points
def get_circle_center(bx, by, cx, cy):
B = bx * bx + by * by
C = cx * cx + cy * cy
D = bx * cy - by * cx
return [(cy * B - by * C) // (2 * D),
(bx * C - cx * B) // (2 * D) ]
# Function to return a unique circle that intersects
# three points
def circle_frOm(A, B,C):
I = get_circle_center(B[0] - A[0], B[1] - A[1],
C[0] - A[0], C[1] - A[1])
I[0] += A[0]
I[1] += A[1]
return [I, dist(I, A)]
# Function to return the smallest circle
# that intersects 2 points
def circle_from(A, B):
# Set the center to be the midpoint of A and B
C = [ (A[0] + B[0]) / 2.0, (A[1] + B[1]) / 2.0]
# Set the radius to be half the distance AB
return [C, dist(A, B) / 2.0]
# Function to check whether a circle encloses the given points
def is_valid_circle(c, P):
# Iterating through all the points to check
# whether the points lie inside the circle or not
for p in P:
if (is_inside(c, p) == False):
return False
return True
# Function to return find the minimum enclosing
# circle from the given set of points
def minimum_enclosing_circle(P):
# To find the number of points
n = len(P)
if (n == 0):
return [[0, 0], 0]
if (n == 1):
return [P[0], 0]
# Set initial MEC to have infinity radius
mec = [[0, 0], INF]
# Go over all pair of points
for i in range(n):
for j in range(i + 1, n):
# Get the smallest circle that
# intersects P[i] and P[j]
tmp = circle_from(P[i], P[j])
# Update MEC if tmp encloses all points
# and has a smaller radius
if (tmp[1] < mec[1] and is_valid_circle(tmp, P)):
mec = tmp
# Go over all triples of points
for i in range(n):
for j in range(i + 1, n):
for k in range(j + 1, n):
# Get the circle that intersects P[i], P[j], P[k]
tmp = circle_frOm(P[i], P[j], P[k])
# Update MEC if tmp encloses all points
# and has smaller radius
if (tmp[1] < mec[1] and is_valid_circle(tmp, P)):
mec = tmp
return mec
# Driver code
mec = minimum_enclosing_circle([ [ 0, 0 ],
[ 0, 1 ],
[ 1, 0 ] ])
print("Center = { ",mec[0][1],",",mec[0][1],
"} Radius = ",round(mec[1],6))
mec2 = minimum_enclosing_circle([ [ 5, -2 ],
[ -3, -2 ],
[ -2, 5 ],
[ 1, 6 ],
[ 0, 2 ] ])
print("Center = {",mec2[0][0],",",mec2[0][1],
"} Radius = ",mec2[1])
# This code is contributed by mohit kumar 29
Center = { 0.5, 0.5 } Radius = 0.707107
Center = { 1, 1 } Radius = 5
时间复杂度:该解决方案的时间复杂度为O(N 4 ) 。那是因为有N 3个三分点。对于每个三元组,我们检查所有点是否都被圆包围。
方法2:使用凸包概念的解决方案也可以用于此问题。想法是首先在给定的点集上形成凸包。一旦执行了凸包并且返回了新的点集,则可以在新的点集上使用上述解决方案来找到MEC。
此方法的代码与上面的代码相同,除了我们还需要首先获取凸包。请参考本文以获得有效的算法来获得凸包。
时间复杂度:需要观察到的一个问题是,如果输入已经代表凸多边形的某些顶点,那么此解决方案将具有与上述幼稚方法相同的时间复杂度。
因此,这种方法的最坏情况下的复杂度仍然是O(N 4 ) 。
但是,如果凸包的顶点数量远小于N,则复杂度将为O(H 4 + NLog(N)) ,其中H表示凸包的顶点数量,而NLog(N)假设使用Graham Scan算法,因素是找到凸包。
最后,如果凸包的顶点数量H非常小,则可以将其视为一个常数因子,因此时间复杂度将为O(NLog(N)) 。
如果您希望与行业专家一起参加现场课程,请参阅《 Geeks现场课程》和《 Geeks现场课程美国》。