先决条件: 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
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)
高效的方法:可以使用旋转卡尺方法优化上述朴素的方法。
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并在area(PN, P1, PK)增加时增加K并在它开始减少之前停止。现在当前点PK可能是P1的对映点。类似地,通过找到area(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)
如果您希望与专家一起参加现场课程,请参阅DSA 现场工作专业课程和学生竞争性编程现场课程。