先决条件: Graham Scan的凸包,方向。
给定坐标平面中的N个点集,任务是找到给定平面集中任意两个点之间的最大距离。
例子:
Input: n = 4, Points: (0, 3), (3, 0), (0, 0), (1, 1)
Output: Maximum Distance = 4.24264
Explanation:
Points having maximum distance between them are (0, 3) and (3, 0)
Input: n = 5, Points: (4, 0), (0, 2), (-1, -7), (1, 10), (2, -3)
Output: Maximum Distance = 17.11724
Explanation:
Points having maximum distance between them are (-1, 7) and (1, 10)
幼稚的方法:幼稚的想法是尝试从给定的集合中每对可能的点进行计算,计算它们之间的距离,并打印所有对之间的最大距离。
下面是上述方法的实现:
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
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)
高效的方法:可以使用“旋转卡尺”方法优化上述幼稚的方法。
Rotating Calipers is a method for solving a number of problems from the field of computational geometry. It resembles the idea of rotating an adjustable caliper around the outside of a polygon’s convex hull. Originally, this method was invented to compute the diameter of convex polygons. It can also be used to compute the minimum and maximum distance between two convex polygons, the intersection of convex polygons, the maximum distance between two points in a polygon, and many things more.
为了实现上述方法,我们将使用凸包的概念。在开始进一步讨论最佳方法之前,我们需要了解以下内容:
- 三角形的无符号区域:如果给定三个点P1(x1,y1),P2(x2,y2)和P3(x3,y3),则
- 是三角形的有符号区域。如果面积为正,则三个点按顺时针顺序排列;否则,它们按逆时针顺序;如果面积等于零,则这些点共线。如果我们取绝对值,那么它将代表三角形的无符号区域。在这里,无符号基本上表示没有方向的区域,即,我们只需要区域的相对绝对值即可。因此,我们可以从公式中删除(1/2)。因此,
Relative Area of Triangle = abs((x2-x1)*(y3-y2)-(x3-x2)*(y2-y1))
- 对映点:那些在直径上完全相反的点。但是对我们而言,对映点是在凸多边形中彼此相距最远的点。如果我们从给定的集合中选择一个点,则只有当我们能够从给定的集合中找到它的对映点时,该点才能达到其最大距离。
步骤如下:
- 具有最大距离的两个点必须位于由给定集合形成的凸多边形的边界上。因此,使用Graham Scan的凸包方法以逆时针顺序排列点。
- 我们有N个点,最初从点P1开始,并包括给定点集中的那些点,这样,通过包括该点集中的任何点,区域的面积始终会增加。
- 从点P1开始,选择K = 2并在面积(PN,P1,PK)增加的同时增加K ,并在开始减少之前停止。现在,当前点PK可能是P1的对映点。类似地,通过找到面积(P1,P2,PK)并递增我们先前停下来的K形式来找到p2的对映点。
- 继续更新每个对映点的最大距离是在上述步骤中发生的,因为初始点和点之间的距离(包括区域在内)是最大的。
下面是上述方法的实现:
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)