📌  相关文章
📜  使用旋转卡尺法计算坐标平面中两点之间的最大距离

📅  最后修改于: 2021-09-06 05:58:36             🧑  作者: Mango

先决条件: Graham Scan 的凸包,方向。
给定坐标平面中的一组N个点,任务是找到给定的一组平面中任意两点之间的最大距离。

例子:

朴素的方法:朴素的想法是尝试给定集合中每对可能的点,并计算每个点之间的距离并打印所有点对之间的最大距离。

下面是上述方法的实现:

C++
#include 
using namespace std;
 
// Function calculates distance
// between two points
long dist(pair p1,
          pair p2)
{
    long x0 = p1.first - p2.first;
    long y0 = p1.second - p2.second;
    return x0 * x0 + y0 * y0;
}
 
// Function to find the maximum
// distance between any two points
double maxDist(pair p[], int n)
{
    double Max = 0;
 
    // Iterate over all possible pairs
    for(int i = 0; i < n; i++)
    {
        for(int j = i + 1; j < n; j++)
        {
             
            // Update max
            Max = max(Max, (double)dist(p[i],
                                        p[j]));
        }
    }
 
    // Return actual distance
    return sqrt(Max);
}
 
// Driver code  
int main()
{
     
    // Number of points
    int n = 5;
 
    pair p[n];
 
    // Given points
    p[0].first = 4, p[0].second = 0;
    p[1].first = 0, p[1].second = 2;
    p[2].first = -1, p[2].second = -7;
    p[3].first = 1, p[3].second = 10;
    p[4].first = 2, p[4].second = -3;
 
    // Function call
    cout << fixed << setprecision(14)
         << maxDist(p, n) <


Java
import java.awt.*;
import java.util.ArrayList;
 
public class Main {
 
    // Function calculates distance
    // between two points
    static long dist(Point p1, Point p2)
    {
        long x0 = p1.x - p2.x;
        long y0 = p1.y - p2.y;
        return x0 * x0 + y0 * y0;
    }
 
    // Function to find the maximum
    // distance between any two points
    static double maxDist(Point p[])
    {
        int n = p.length;
        double max = 0;
 
        // Iterate over all possible pairs
        for (int i = 0; i < n; i++) {
 
            for (int j = i + 1; j < n; j++) {
 
                // Update max
                max = Math.max(max,
                               dist(p[i],
                                    p[j]));
            }
        }
 
        // Return actual distance
        return Math.sqrt(max);
    }
 
    // Driver Code
    public static void main(String[] args)
    {
        // Number of points
        int n = 5;
 
        Point p[] = new Point[n];
 
        // Given points
        p[0] = new Point(4, 0);
        p[1] = new Point(0, 2);
        p[2] = new Point(-1, -7);
        p[3] = new Point(1, 10);
        p[4] = new Point(2, -3);
 
        // Function Call
        System.out.println(maxDist(p));
    }
}


Python3
from math import sqrt
 
# Function calculates distance
# between two points
def dist(p1, p2):
     
    x0 = p1[0] - p2[0]
    y0 = p1[1] - p2[1]
    return x0 * x0 + y0 * y0
 
# Function to find the maximum
# distance between any two points
def maxDist(p):
 
    n = len(p)
    maxm = 0
 
    # Iterate over all possible pairs
    for i in range(n):
        for j in range(i + 1, n):
             
            # Update maxm
            maxm = max(maxm, dist(p[i], p[j]))
 
    # Return actual distance
    return sqrt(maxm)
     
# Driver Code
if __name__ == '__main__':
     
    # Number of points
    n = 5
 
    p = []
     
    # Given points
    p.append([4, 0])
    p.append([0, 2])
    p.append([-1, -7])
    p.append([1, 10])
    p.append([2, -3])
 
    # Function Call
    print(maxDist(p))
 
# This code is contributed by mohit kumar 29


C#
using System;
class GFG {
     
    // Function calculates distance
    // between two points
    static long dist(Tuple p1, Tuple p2)
    {
        long x0 = p1.Item1 - p2.Item1;
        long y0 = p1.Item2 - p2.Item2;
        return x0 * x0 + y0 * y0;
    }
  
    // Function to find the maximum
    // distance between any two points
    static double maxDist(Tuple[] p)
    {
        int n = p.Length;
        double max = 0;
  
        // Iterate over all possible pairs
        for (int i = 0; i < n; i++) {
  
            for (int j = i + 1; j < n; j++) {
  
                // Update max
                max = Math.Max(max, dist(p[i],p[j]));
            }
        }
  
        // Return actual distance
        return Math.Sqrt(max);
    }
 
  // Driver code
  static void Main() {
      
        // Given points
        Tuple[] p =
        {
            Tuple.Create(4, 0),
            Tuple.Create(0, 2),
            Tuple.Create(-1, -7),
            Tuple.Create(1, 10),
            Tuple.Create(2, -3),
        };
       
        // Function Call
        Console.WriteLine(maxDist(p));
  }
}
 
// This code is contributed by divyesh072019


Javascript


Java
// Java Program for the above approach
import java.awt.*;
import java.util.*;
import java.util.Map.Entry;
 
public class Main {
 
    // Function to detect the orientation
    static int orientation(Point p,
                           Point q,
                           Point r)
    {
        int x = area(p, q, r);
 
        // If area > 0 then
        // points are clockwise
        if (x > 0) {
            return 1;
        }
 
        // If area<0 then
        // points are counterclockwise
        if (x < 0) {
            return -1;
        }
 
        // If area is 0 then p, q
        // and r are co-linear
        return 0;
    }
 
    // Function to find the area
    static int area(Point p, Point q, Point r)
    {
        // 2*(area of triangle)
        return ((p.y - q.y) * (q.x - r.x)
                - (q.y - r.y) * (p.x - q.x));
    }
 
    // Function to find the absolute Area
    static int absArea(Point p,
                       Point q, Point r)
    {
        // Unsigned area
        // 2*(area of triangle)
        return Math.abs(area(p, q, r));
    }
 
    // Function to find the distance
    static int dist(Point p1, Point p2)
    {
        // squared-distance b/w
        // p1 and p2 for precision
        return ((p1.x - p2.x) * (p1.x - p2.x)
                + (p1.y - p2.y) * (p1.y - p2.y));
    }
 
    // Function to implement Convex Hull
    // Approach
    static ArrayList
    convexHull(Point points[])
    {
        int n = points.length;
 
        Point min = new Point(Integer.MAX_VALUE,
                              Integer.MAX_VALUE);
 
        // Choose point having min.
        // y-coordinate and if two points
        // have same y-coordinate choose
        // the one with minimum x-coordinate
        int ind = -1;
 
        // Iterate Points[]
        for (int i = 0; i < n; i++) {
            if (min.y > points[i].y) {
                min.y = points[i].y;
                min.x = points[i].x;
                ind = i;
            }
            else if (min.y == points[i].y
                     && min.x > points[i].x) {
                min.x = points[i].x;
                ind = i;
            }
        }
        points[ind] = points[0];
        points[0] = min;
 
        // Sort points which have
        // minimum polar angle wrt
        // Point min
        Arrays.sort(points, 1, n,
                    new Comparator() {
 
                        @Override
                        public int compare(Point o1,
                                           Point o2)
                        {
 
                            int o = orientation(min, o1, o2);
 
                            // If points are co-linear
                            // choose the one having smaller
                            // distance with min first.
                            if (o == 0) {
                                return dist(o1, min)
                                    - dist(o2, min);
                            }
 
                            // If clockwise then swap
                            if (o == 1) {
                                return 1;
                            }
 
                            // If anticlockwise then
                            // don't swap
                            return -1;
                        }
                    });
 
        Stack st = new Stack<>();
 
        // First hull point
        st.push(points[0]);
 
        int k;
        for (k = 1; k < n - 1; k++) {
            if (orientation(points[0],
                            points[k],
                            points[k + 1])
                != 0)
                break;
        }
 
        // Second hull point
        st.push(points[k]);
 
        for (int i = k + 1; i < n; i++) {
            Point top = st.pop();
 
            while (orientation(st.peek(),
                               top,
                               points[i])
                   >= 0) {
                top = st.pop();
            }
 
            st.push(top);
            st.push(points[i]);
        }
 
        ArrayList hull
            = new ArrayList<>();
 
        // Iterate stack and add node to hull
        for (int i = 0; i < st.size(); i++) {
            hull.add(st.get(i));
        }
        return hull;
    }
 
    // Function to find the maximum
    // distance between any two points
    // from a set of given points
    static double
    rotatingCaliper(Point points[])
    {
        // Takes O(n)
        ArrayList convexHull
            = convexHull(points);
        int n = convexHull.size();
 
        // Convex hull point in counter-
        // clockwise order
        Point hull[] = new Point[n];
        n = 0;
 
        while (n < convexHull.size()) {
            hull[n] = convexHull.get(n++);
        }
 
        // Base Cases
        if (n == 1)
            return 0;
        if (n == 2)
            return Math.sqrt(dist(hull[0], hull[1]));
        int k = 1;
 
        // Find the farthest vertex
        // from hull[0] and hull[n-1]
        while (absArea(hull[n - 1],
                       hull[0],
                       hull[(k + 1) % n])
               > absArea(hull[n - 1],
                         hull[0],
                         hull[k])) {
            k++;
        }
 
        double res = 0;
 
        // Check points from 0 to k
        for (int i = 0, j = k;
             i <= k && j < n; i++) {
            res = Math.max(res,
                           Math.sqrt((double)dist(hull[i],
                                                  hull[j])));
 
            while (j < n
                   && absArea(hull[i],
                              hull[(i + 1) % n],
                              hull[(j + 1) % n])
                          > absArea(hull[i],
                                    hull[(i + 1) % n],
                                    hull[j])) {
 
                // Update res
                res = Math.max(
                    res,
                    Math.sqrt(dist(hull[i],
                                   hull[(j + 1) % n])));
                j++;
            }
        }
 
        // Return the result distance
        return res;
    }
 
    // Driver Code
    public static void main(String[] args)
    {
        // Total points
        int n = 5;
        Point p[] = new Point[n];
 
        // Given Points
        p[0] = new Point(4, 0);
        p[1] = new Point(0, 2);
        p[2] = new Point(-1, -7);
        p[3] = new Point(1, 10);
        p[4] = new Point(2, -3);
 
        // Function Call
        System.out.println(rotatingCaliper(p));
    }
}


输出:
17.11724276862369

时间复杂度: O(N 2 ),其中 N 是点的总数。
辅助空间: O(1)

高效的方法:可以使用旋转卡尺方法优化上述朴素的方法

为了实现上述方法,我们将使用凸包的概念。在我们开始进一步讨论最佳方法之前,我们需要了解以下内容:

  • 三角形的无符号面积:如果给定三个点P1(x1, y1), P2(x2, y2)P3(x3, y3)那么

\left ( \frac {(x2 - x1)*(y3 - y2) - (x3 - x2)*(y2 - y1)}{2} \right )

  • 是三角形的有符号面积。如果面积为正,则三个点按顺时针顺序排列,否则它们按逆时针顺序排列,如果面积等于零,则这些点共线。如果我们取绝对值,那么这将代表三角形的无符号区域。这里,无符号基本上是指没有方向的区域,即我们只需要该区域的相对绝对值。因此,我们可以从公式中删除 (1/2)。因此,
  • 对映点:是那些彼此完全相反的点。但对我们来说,对映点是凸多边形中相距最远的点。如果我们从给定的集合中选择一个点,那么当且仅当我们可以从给定的集合中找到它的对映点时,这个点才能达到它的最大距离。

以下是步骤:

  1. 具有最大距离的两个点必须位于由给定集合形成的凸多边形的边界上。因此,使用 Graham Scan 的凸包方法按逆时针顺序排列点。
  2. 我们有N个点,最初从点P1开始,包括来自给定点集合的那些点,这样区域的面积总是通过包含集合中的任何点而增加。
  3. 从点P1开始,选择K = 2并在area(PN, P1, PK)增加时增加K并在它开始减少之前停止。现在当前点PK可能是P1的对映点。类似地,通过找到area(P1, P2, PK)并增加我们之前停止的K形式,找到 p2 的对映点,依此类推。
  4. 继续更新每个对映点的最大距离在上述步骤中发生,因为包括面积的初始点和点之间的距离是最大的。

下面是上述方法的实现:

Java

// Java Program for the above approach
import java.awt.*;
import java.util.*;
import java.util.Map.Entry;
 
public class Main {
 
    // Function to detect the orientation
    static int orientation(Point p,
                           Point q,
                           Point r)
    {
        int x = area(p, q, r);
 
        // If area > 0 then
        // points are clockwise
        if (x > 0) {
            return 1;
        }
 
        // If area<0 then
        // points are counterclockwise
        if (x < 0) {
            return -1;
        }
 
        // If area is 0 then p, q
        // and r are co-linear
        return 0;
    }
 
    // Function to find the area
    static int area(Point p, Point q, Point r)
    {
        // 2*(area of triangle)
        return ((p.y - q.y) * (q.x - r.x)
                - (q.y - r.y) * (p.x - q.x));
    }
 
    // Function to find the absolute Area
    static int absArea(Point p,
                       Point q, Point r)
    {
        // Unsigned area
        // 2*(area of triangle)
        return Math.abs(area(p, q, r));
    }
 
    // Function to find the distance
    static int dist(Point p1, Point p2)
    {
        // squared-distance b/w
        // p1 and p2 for precision
        return ((p1.x - p2.x) * (p1.x - p2.x)
                + (p1.y - p2.y) * (p1.y - p2.y));
    }
 
    // Function to implement Convex Hull
    // Approach
    static ArrayList
    convexHull(Point points[])
    {
        int n = points.length;
 
        Point min = new Point(Integer.MAX_VALUE,
                              Integer.MAX_VALUE);
 
        // Choose point having min.
        // y-coordinate and if two points
        // have same y-coordinate choose
        // the one with minimum x-coordinate
        int ind = -1;
 
        // Iterate Points[]
        for (int i = 0; i < n; i++) {
            if (min.y > points[i].y) {
                min.y = points[i].y;
                min.x = points[i].x;
                ind = i;
            }
            else if (min.y == points[i].y
                     && min.x > points[i].x) {
                min.x = points[i].x;
                ind = i;
            }
        }
        points[ind] = points[0];
        points[0] = min;
 
        // Sort points which have
        // minimum polar angle wrt
        // Point min
        Arrays.sort(points, 1, n,
                    new Comparator() {
 
                        @Override
                        public int compare(Point o1,
                                           Point o2)
                        {
 
                            int o = orientation(min, o1, o2);
 
                            // If points are co-linear
                            // choose the one having smaller
                            // distance with min first.
                            if (o == 0) {
                                return dist(o1, min)
                                    - dist(o2, min);
                            }
 
                            // If clockwise then swap
                            if (o == 1) {
                                return 1;
                            }
 
                            // If anticlockwise then
                            // don't swap
                            return -1;
                        }
                    });
 
        Stack st = new Stack<>();
 
        // First hull point
        st.push(points[0]);
 
        int k;
        for (k = 1; k < n - 1; k++) {
            if (orientation(points[0],
                            points[k],
                            points[k + 1])
                != 0)
                break;
        }
 
        // Second hull point
        st.push(points[k]);
 
        for (int i = k + 1; i < n; i++) {
            Point top = st.pop();
 
            while (orientation(st.peek(),
                               top,
                               points[i])
                   >= 0) {
                top = st.pop();
            }
 
            st.push(top);
            st.push(points[i]);
        }
 
        ArrayList hull
            = new ArrayList<>();
 
        // Iterate stack and add node to hull
        for (int i = 0; i < st.size(); i++) {
            hull.add(st.get(i));
        }
        return hull;
    }
 
    // Function to find the maximum
    // distance between any two points
    // from a set of given points
    static double
    rotatingCaliper(Point points[])
    {
        // Takes O(n)
        ArrayList convexHull
            = convexHull(points);
        int n = convexHull.size();
 
        // Convex hull point in counter-
        // clockwise order
        Point hull[] = new Point[n];
        n = 0;
 
        while (n < convexHull.size()) {
            hull[n] = convexHull.get(n++);
        }
 
        // Base Cases
        if (n == 1)
            return 0;
        if (n == 2)
            return Math.sqrt(dist(hull[0], hull[1]));
        int k = 1;
 
        // Find the farthest vertex
        // from hull[0] and hull[n-1]
        while (absArea(hull[n - 1],
                       hull[0],
                       hull[(k + 1) % n])
               > absArea(hull[n - 1],
                         hull[0],
                         hull[k])) {
            k++;
        }
 
        double res = 0;
 
        // Check points from 0 to k
        for (int i = 0, j = k;
             i <= k && j < n; i++) {
            res = Math.max(res,
                           Math.sqrt((double)dist(hull[i],
                                                  hull[j])));
 
            while (j < n
                   && absArea(hull[i],
                              hull[(i + 1) % n],
                              hull[(j + 1) % n])
                          > absArea(hull[i],
                                    hull[(i + 1) % n],
                                    hull[j])) {
 
                // Update res
                res = Math.max(
                    res,
                    Math.sqrt(dist(hull[i],
                                   hull[(j + 1) % n])));
                j++;
            }
        }
 
        // Return the result distance
        return res;
    }
 
    // Driver Code
    public static void main(String[] args)
    {
        // Total points
        int n = 5;
        Point p[] = new Point[n];
 
        // Given Points
        p[0] = new Point(4, 0);
        p[1] = new Point(0, 2);
        p[2] = new Point(-1, -7);
        p[3] = new Point(1, 10);
        p[4] = new Point(2, -3);
 
        // Function Call
        System.out.println(rotatingCaliper(p));
    }
}
输出:
17.11724276862369

时间复杂度: O(N*log N)
辅助空间: O(N)

如果您想与行业专家一起参加直播课程,请参阅Geeks Classes Live