Círculo envolvente mínimo | Serie 1

Prerrequisitos: Ecuación del círculo cuando se dan tres puntos en el círculo , Casco convexo
Dada una array arr[][] que contiene N puntos en un plano 2-D con coordenadas enteras. La tarea es encontrar el centro y el radio del círculo envolvente mínimo (MEC). Un círculo envolvente mínimo es un círculo en el que todos los puntos se encuentran dentro del círculo o en sus límites.
Ejemplos: 
 

Entrada: arr[][] = {{0, 0}, {0, 1}, {1, 0}} Salida 
: Centro = {0.5, 0.5}, Radio = 0.7071 
Explicación: 
Al trazar el círculo anterior con radio 0.707 y centro (0.5, 0.5), se puede observar claramente que todos los puntos mencionados se encuentran dentro o sobre el círculo. 
 

Entrada: arr[][] = {{5, -2}, {-3, -2}, {-2, 5}, {1, 6}, {0, 2}} Salida: Centro = { 
1.0 , 1.0}, Radio = 5.000 
 

Enfoque ingenuo: este problema se puede resolver haciendo algunas observaciones. 
 

  • La primera observación que se puede hacer es que el MEC corta al menos un punto. Esto se debe a que si el MEC no se interseca en ningún punto, el círculo podría reducirse aún más hasta que se interseque en uno de los puntos.
  • La segunda observación que se puede hacer es que, dado un círculo que encierra todos los puntos y se interseca en un solo punto, el círculo se puede reducir aún más moviendo el centro hacia ese punto mientras se mantiene el punto en el límite del círculo hasta que el círculo se interseca con uno. o más puntos adicionales.
  • Si el círculo se interseca en dos puntos (A y B) y la distancia AB es igual al diámetro del círculo, entonces el círculo no se puede encoger más. De lo contrario, el centro del círculo se puede mover hacia el punto medio de AB hasta que el círculo se cruza con un tercer punto (en el que el círculo ya no se puede contraer).

De las observaciones anteriores, se puede concluir que el MEC: 
 

  1. Intersecta 2 puntos A y B, donde AB = diámetro del círculo. Para este caso, el centro del círculo sería el punto medio de A y B y el radio sería la mitad de la distancia AB .
  2. Intersecta 3 o más puntos. El enfoque para encontrar el centro y el radio se ha discutido en este artículo .

Por lo tanto, la solución a este problema es trivial para N <= 3. Para otros casos, se puede formar una idea simple para resolver este problema. La idea es usar todos los pares y triples de puntos para obtener el círculo definido por esos puntos. Después de obtener el círculo, prueba para ver si los otros puntos están encerrados por ese círculo y devuelve el círculo válido más pequeño encontrado.
A continuación se muestra la implementación del enfoque anterior:
 

CPP

// C++ program to find the minimum enclosing
// circle for N integer points in a 2-D plane
#include <iostream>
#include <math.h>
#include <vector>
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<Point>& 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<Point>& 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
Producción: 

Center = { 0.5, 0.5 } Radius = 0.707107
Center = { 1, 1 } Radius = 5

 

Complejidad de tiempo: La complejidad de tiempo para esta solución sería de O(N 4 ) . Eso es porque hay N 3 triples de puntos. Y para cada triple, verificamos si todos los puntos están encerrados por el círculo.
Enfoque 2: También se puede utilizar una solución con la aplicación del concepto de casco convexo para este problema. La idea es formar primero un casco convexo en el conjunto de puntos dado. Una vez que se realiza el casco convexo y se devuelve el nuevo conjunto de puntos, la solución mencionada anteriormente se puede usar en el nuevo conjunto de puntos para encontrar el MEC.
El código para este enfoque sería el mismo que el anterior, excepto que también necesitaríamos obtener primero el casco convexo. Por favor, consulte este artículopara un algoritmo eficiente para obtener el casco convexo.
Complejidad de tiempo: una observación que debe hacerse es que si la entrada ya representa algunos vértices de un polígono convexo, entonces esta solución tendría la misma complejidad de tiempo que el enfoque ingenuo anterior. 
Por lo tanto, la complejidad del caso más desfavorable de este enfoque sigue siendo O(N 4 ) .
Sin embargo, si el número de vértices del casco convexo es considerablemente menor que N, entonces la complejidad sería O(H 4 + NLog(N)) donde H representa el número de vértices del casco convexo, y NLog(N) El factor es para encontrar el casco convexo asumiendo que se usa el algoritmo Graham Scan .
Finalmente, si el número de vértices, H , del casco convexo es muy pequeño, entonces puede considerarse como un factor constante y, por lo tanto, la complejidad temporal sería O(NLog(N)) .
 

Publicación traducida automáticamente

Artículo escrito por marwan tammam y traducido por Barcelona Geeks. The original can be accessed here. Licence: CCBY-SA

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *