Par de puntos más cercano | Implementación de O (inicio de sesión)

Tenemos una array de n puntos en el plano, y el problema es encontrar el par de puntos más cercano en la array. Este problema surge en varias aplicaciones. Por ejemplo, en el control del tráfico aéreo, es posible que desee controlar los aviones que se acercan demasiado, ya que esto puede indicar una posible colisión. Recuerda la siguiente fórmula para la distancia entre dos puntos p y q. 
\left \| pq\right \| = \sqrt{(p_x - q_x)^2 + (p_y - q_y)^2}
Hemos discutido una solución de divide y vencerás para este problema. La complejidad de tiempo de la implementación proporcionada en la publicación anterior es O(n (Log)^2). En esta publicación, discutimos la implementación con complejidad de tiempo como O (nLogn). 
El siguiente es un resumen del algoritmo discutido en la publicación anterior.
1) Ordenamos todos los puntos según las coordenadas x.
2)Divide todos los puntos en dos mitades.
3) Encuentre recursivamente las distancias más pequeñas en ambos subarreglos.
4) Tomar el mínimo de las dos distancias más pequeñas. Sea el mínimo d. 
5) Cree una tira de array [] que almacene todos los puntos que estén a una distancia máxima de d de la línea central que divide los dos conjuntos.
6) Encuentra la distancia más pequeña en strip[]. 
7) Devuelva el mínimo de d y la distancia más pequeña calculada en el paso 6 anterior.
Lo bueno del enfoque anterior es que, si la array strip[] se ordena de acuerdo con la coordenada y, entonces podemos encontrar la distancia más pequeña en strip[] en tiempo O(n). En la implementación discutida en la publicación anterior, strip[] se clasificó explícitamente en cada llamada recursiva que hizo que la complejidad del tiempo fuera O(n (Logn)^2), asumiendo que el paso de clasificación toma el tiempo O(nLogn). 
En esta publicación, discutimos una implementación donde la complejidad del tiempo es O (nLogn). La idea es preordenar todos los puntos según las coordenadas y. Deje que la array ordenada sea Py[]. Cuando hacemos llamadas recursivas, necesitamos dividir los puntos de Py[] también según la línea vertical. Podemos hacerlo simplemente procesando cada punto y comparando su coordenada x con la coordenada x de la línea media.
A continuación se muestra la implementación en C++ del enfoque O(nLogn).
 

CPP

// A divide and conquer program in C++ to find the smallest distance from a
// given set of points.
 
#include <iostream>
#include <float.h>
#include <stdlib.h>
#include <math.h>
using namespace std;
 
// A structure to represent a Point in 2D plane
struct Point
{
    int x, y;
};
 
 
/* Following two functions are needed for library function qsort().
   Refer: http://www.cplusplus.com/reference/clibrary/cstdlib/qsort/ */
 
// Needed to sort array of points according to X coordinate
int compareX(const void* a, const void* b)
{
    Point *p1 = (Point *)a,  *p2 = (Point *)b;
    return (p1->x != p2->x) ? (p1->x - p2->x) : (p1->y - p2->y);
}
// Needed to sort array of points according to Y coordinate
int compareY(const void* a, const void* b)
{
    Point *p1 = (Point *)a,   *p2 = (Point *)b;
    return (p1->y != p2->y) ? (p1->y - p2->y) : (p1->x - p2->x);
}
 
// A utility function to find the distance between two points
float dist(Point p1, Point p2)
{
    return sqrt( (p1.x - p2.x)*(p1.x - p2.x) +
                 (p1.y - p2.y)*(p1.y - p2.y)
               );
}
 
// A Brute Force method to return the smallest distance between two points
// in P[] of size n
float bruteForce(Point P[], int n)
{
    float min = FLT_MAX;
    for (int i = 0; i < n; ++i)
        for (int j = i+1; j < n; ++j)
            if (dist(P[i], P[j]) < min)
                min = dist(P[i], P[j]);
    return min;
}
 
// A utility function to find a minimum of two float values
float min(float x, float y)
{
    return (x < y)? x : y;
}
 
 
// A utility function to find the distance between the closest points of
// strip of a given size. All points in strip[] are sorted according to
// y coordinate. They all have an upper bound on minimum distance as d.
// Note that this method seems to be a O(n^2) method, but it's a O(n)
// method as the inner loop runs at most 6 times
float stripClosest(Point strip[], int size, float d)
{
    float min = d;  // Initialize the minimum distance as d
 
    // Pick all points one by one and try the next points till the difference
    // between y coordinates is smaller than d.
    // This is a proven fact that this loop runs at most 6 times
    for (int i = 0; i < size; ++i)
        for (int j = i+1; j < size && (strip[j].y - strip[i].y) < min; ++j)
            if (dist(strip[i],strip[j]) < min)
                min = dist(strip[i], strip[j]);
 
    return min;
}
 
// A recursive function to find the smallest distance. The array Px contains
// all points sorted according to x coordinates and Py contains all points
// sorted according to y coordinates
float closestUtil(Point Px[], Point Py[], int n)
{
    // If there are 2 or 3 points, then use brute force
    if (n <= 3)
        return bruteForce(Px, n);
 
    // Find the middle point
    int mid = n/2;
    Point midPoint = Px[mid];
 
 
    // Divide points in y sorted array around the vertical line.
    // Assumption: All x coordinates are distinct.
    Point Pyl[mid];   // y sorted points on left of vertical line
    Point Pyr[n-mid];  // y sorted points on right of vertical line
    int li = 0, ri = 0;  // indexes of left and right subarrays
    for (int i = 0; i < n; i++)
    {
      if ((Py[i].x < midPoint.x || (Py[i].x == midPoint.x && Py[i].y < midPoint.y)) && li<mid)
         Pyl[li++] = Py[i];
      else
         Pyr[ri++] = Py[i];
    }
 
    // Consider the vertical line passing through the middle point
    // calculate the smallest distance dl on left of middle point and
    // dr on right side
    float dl = closestUtil(Px, Pyl, mid);
    float dr = closestUtil(Px + mid, Pyr, n-mid);
 
    // Find the smaller of two distances
    float d = min(dl, dr);
 
    // Build an array strip[] that contains points close (closer than d)
    // to the line passing through the middle point
    Point strip[n];
    int j = 0;
    for (int i = 0; i < n; i++)
        if (abs(Py[i].x - midPoint.x) < d)
            strip[j] = Py[i], j++;
 
    // Find the closest points in strip.  Return the minimum of d and closest
    // distance is strip[]
    return stripClosest(strip, j, d);
}
 
// The main function that finds the smallest distance
// This method mainly uses closestUtil()
float closest(Point P[], int n)
{
    Point Px[n];
    Point Py[n];
    for (int i = 0; i < n; i++)
    {
        Px[i] = P[i];
        Py[i] = P[i];
    }
 
    qsort(Px, n, sizeof(Point), compareX);
    qsort(Py, n, sizeof(Point), compareY);
 
    // Use recursive function closestUtil() to find the smallest distance
    return closestUtil(Px, Py, n);
}
 
// Driver program to test above functions
int main()
{
    Point P[] = {{2, 3}, {12, 30}, {40, 50}, {5, 1}, {12, 10}, {3, 4}};
    int n = sizeof(P) / sizeof(P[0]);
    cout << "The smallest distance is " << closest(P, n);
    return 0;
}
Producción

The smallest distance is 1.41421

Complejidad de tiempo: Deje que la complejidad de tiempo del algoritmo anterior sea T (n). Supongamos que usamos un algoritmo de clasificación O(nLogn). El algoritmo anterior divide todos los puntos en dos conjuntos y llama recursivamente a dos conjuntos. Después de dividir, encuentra la tira en tiempo O(n). Además, lleva O(n) tiempo dividir la array Py alrededor de la línea vertical media. Finalmente encuentra los puntos más cercanos en la franja en tiempo O(n). Entonces T(n) se puede expresar de la siguiente manera 
T(n) = 2T(n/2) + O(n) + O(n) + O(n) 
T(n) = 2T(n/2) + O( n) 
T(n) = T(nLog)

Espacio auxiliar: O(log n), ya que se crea una pila implícita durante las llamadas recursivas
Referencias:  
http://www.cs.umd.edu/class/fall2013/cmsc451/Lects/lect10.pdf  
http://www.youtube. com/watch?v=vS4Zn1a9KUc  
http://www.youtube.com/watch?v=T3T7T8Ym20M  
http://en.wikipedia.org/wiki/Closest_pair_of_points_problem
Escriba comentarios si encuentra algo incorrecto o si desea compartir más información sobre el tema tratado anteriormente
 

Publicación traducida automáticamente

Artículo escrito por GeeksforGeeks-1 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 *