如果您喜欢此文章,请收藏、点赞、评论,谢谢,祝您快乐每一天。

给定一个固定的点集,我们需要找到该点集的凸包。此外,我们还需要找到从该点集中移除一个点后得到的凸包。
例子:
初始点集:(-2, 8) (-1, 2) (0, 1) (1, 0)
(-3, 0) (-1, -9) (2, -6) (3, 0)
(5, 3) (2, 5)
初始凸包:(-2, 8) (-3, 0) (-1, -9) (2, -6)
(5, 3)
从点集中移除的点:(-2, 8)
最终凸包:(2, 5) (-3, 0) (-1, -9) (2, -6) (5, 3)
前提条件:凸包(简单的分治算法)
JavaScript 利用分治算法求凸包:JavaScript 利用分治算法求凸包(Convex Hull using Divide and Conquer Algorithm)-CSDN博客
C# 利用分治算法求凸包:C# 利用分治算法求凸包(Convex Hull using Divide and Conquer Algorithm)-CSDN博客
Python 利用分治算法求凸包:Python 利用分治算法求凸包(Convex Hull using Divide and Conquer Algorithm)-CSDN博客
Java 利用分治算法求凸包:Java 利用分治算法求凸包(Convex Hull using Divide and Conquer Algorithm)-CSDN博客
C++ 利用分治算法求凸包:C++ 利用分治算法求凸包(Convex Hull using Divide and Conquer Algorithm)-CSDN博客
解决上述问题的算法非常简单。我们只需检查要移除的点是否属于凸包。如果是,则必须从初始集合中移除该点,然后重新构建凸包(参见上面凸包(分治))。
如果不是这样,那么我们已经有了解决方案(凸包不会改变)。
using System;
using System.Collections.Generic;
class Pair : IComparable<Pair>
{
public int First { get; set; }
public int Second { get; set; }
public Pair(int first, int second)
{
First = first;
Second = second;
}
public int CompareTo(Pair other)
{
if (First != other.First)
{
return First - other.First;
}
return Second - other.Second;
}
}
class ConvexHull
{
// Stores the center of the polygon (made global because it is used in the Compare function)
static Pair mid = new Pair(0, 0);
// Determines the quadrant of a point (used in Compare())
static int Quad(Pair p)
{
if (p.First >= 0 && p.Second >= 0)
{
return 1;
}
if (p.First <= 0 && p.Second >= 0)
{
return 2;
}
if (p.First <= 0 && p.Second <= 0)
{
return 3;
}
return 4;
}
// Checks whether the line is crossing the polygon
static int Orientation(Pair a, Pair b, Pair c)
{
int res = (b.Second - a.Second) * (c.First - b.First) - (c.Second - b.Second) * (b.First - a.First);
if (res == 0)
{
return 0;
}
if (res > 0)
{
return 1;
}
return -1;
}
// Compare function for sorting
static int Compare(Pair p1, Pair p2)
{
Pair p = new Pair(p1.First - mid.First, p1.Second - mid.Second);
Pair q = new Pair(p2.First - mid.First, p2.Second - mid.Second);
int one = Quad(p);
int two = Quad(q);
if (one != two)
{
return one - two;
}
return Math.Sign(p.Second * q.First - q.Second * p.First);
}
// Finds upper tangent of two polygons 'a' and 'b' represented as two lists.
static List<Pair> Merger(List<Pair> a, List<Pair> b)
{
int n1 = a.Count;
int n2 = b.Count;
int ia = 0, ib = 0;
for (int i = 1; i < n1; i++)
{
if (ai.First > aia.First)
{
ia = i;
}
}
for (int i = 1; i < n2; i++)
{
if (bi.First < bib.First)
{
ib = i;
}
}
int inda = ia, indb = ib;
bool done = false;
while (!done)
{
done = true;
while (Orientation(bindb, ainda, a(inda + 1) % n1) >= 0)
{
inda = (inda + 1) % n1;
}
while (Orientation(ainda, bindb, b(n2 + indb - 1) % n2) <= 0)
{
indb = (n2 + indb - 1) % n2;
done = false;
}
}
int uppera = inda, upperb = indb;
inda = ia;
indb = ib;
done = false;
while (!done)
{
done = true;
while (Orientation(ainda, bindb, b(indb + 1) % n2) >= 0)
{
indb = (indb + 1) % n2;
}
while (Orientation(bindb, ainda, a(n1 + inda - 1) % n1) <= 0)
{
inda = (n1 + inda - 1) % n1;
done = false;
}
}
int lowera = inda, lowerb = indb;
List<Pair> ret = new List<Pair>();
int ind = uppera;
ret.Add(auppera);
while (ind != lowera)
{
ind = (ind + 1) % n1;
ret.Add(aind);
}
ind = lowerb;
ret.Add(blowerb);
while (ind != upperb)
{
ind = (ind + 1) % n2;
ret.Add(bind);
}
return ret;
}
// Brute force algorithm to find convex hull for a set of less than 6 points
static List<Pair> BruteHull(List<Pair> a)
{
HashSet<Pair> s = new HashSet<Pair>();
for (int i = 0; i < a.Count; i++)
{
for (int j = i + 1; j < a.Count; j++)
{
int x1 = ai.First, x2 = aj.First;
int y1 = ai.Second, y2 = aj.Second;
int a1 = y1 - y2;
int b1 = x2 - x1;
int c1 = x1 * y2 - y1 * x2;
int pos = 0, neg = 0;
foreach (var k in a)
{
if (a1 * k.First + b1 * k.Second + c1 <= 0)
{
neg++;
}
if (a1 * k.First + b1 * k.Second + c1 >= 0)
{
pos++;
}
}
if (pos == a.Count || neg == a.Count)
{
s.Add(ai);
s.Add(aj);
}
}
}
List<Pair> ret = new List<Pair>(s);
mid = new Pair(0, 0);
int n = ret.Count;
for (int i = 0; i < n; i++)
{
mid.First += reti.First;
mid.Second += reti.Second;
reti.First *= n;
reti.Second *= n;
}
ret.Sort(Compare);
for (int i = 0; i < n; i++)
{
reti.First /= n;
reti.Second /= n;
}
return ret;
}
// Returns the convex hull for the given set of points
static List<Pair> FindHull(List<Pair> a)
{
if (a.Count <= 5)
{
return BruteHull(a);
}
List<Pair> left = new List<Pair>();
List<Pair> right = new List<Pair>();
for (int i = 0; i < a.Count / 2; i++)
{
left.Add(ai);
}
for (int i = a.Count / 2; i < a.Count; i++)
{
right.Add(ai);
}
List<Pair> leftHull = FindHull(left);
List<Pair> rightHull = FindHull(right);
return Merger(leftHull, rightHull);
}
// Returns the convex hull for the given set of points after removing a point p.
static List<Pair> RemovePoint(List<Pair> a, List<Pair> hull, Pair p)
{
bool found = false;
for (int i = 0; i < hull.Count && !found; i++)
{
if (hulli.First == p.First && hulli.Second == p.Second)
{
found = true;
}
}
if (!found)
{
return hull;
}
for (int i = 0; i < a.Count; i++)
{
if (ai.First == p.First && ai.Second == p.Second)
{
a.RemoveAt(i);
break;
}
}
a.Sort(Compare);
return FindHull(a);
}
// Driver code
public static void Main(string\[\] args)
{
List<Pair> a = new List<Pair>();
a.Add(new Pair(0, 0));
a.Add(new Pair(1, -4));
a.Add(new Pair(-1, -5));
a.Add(new Pair(-5, -3));
a.Add(new Pair(-3, -1));
a.Add(new Pair(-1, -3));
a.Add(new Pair(-2, -2));
a.Add(new Pair(-1, -1));
a.Add(new Pair(-2, -1));
a.Add(new Pair(-1, 1));
// Sorting the set of points according to the x-coordinate
a.Sort();
List<Pair> hull = FindHull(a);
Console.WriteLine("Convex hull:");
foreach (var e in hull)
{
Console.WriteLine($"{e.First} {e.Second}");
}
Pair p = new Pair(-5, -3);
hull = RemovePoint(a, hull, p);
Console.WriteLine("\nModified Convex Hull:");
foreach (var e in hull)
{
Console.WriteLine($"{e.First} {e.Second}");
}
}
}
输出:
凸包(convex hull):
-3 0
-1 -9
2 -6
5 3
2 5
**时间复杂度:**很容易看出,每次查询所花费的最大时间是构建凸包所需的时间,即 O(n*logn)。因此,总复杂度为 O(q*n*logn),其中 q 为要删除的点数。
辅助空间: O(n),因为占用了 n 个额外的空间。
如果您喜欢此文章,请收藏、点赞、评论,谢谢,祝您快乐每一天。