news 2026/7/28 1:27:36

C++ 从凸包中删除点(Deleting points from Convex Hull)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
C++ 从凸包中删除点(Deleting points from Convex Hull)

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

给定一个固定的点集,我们需要找到该点集的凸包。此外,我们还需要找到从该点集中移除一个点后得到的凸包。

例子:

初始点集:(-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 利用分治算法求凸包:https://blog.csdn.net/hefeng_aspnet/article/details/160184183
C# 利用分治算法求凸包:https://blog.csdn.net/hefeng_aspnet/article/details/160184134
Python 利用分治算法求凸包:https://blog.csdn.net/hefeng_aspnet/article/details/160184105
Java 利用分治算法求凸包:https://blog.csdn.net/hefeng_aspnet/article/details/160184068
C++ 利用分治算法求凸包:https://blog.csdn.net/hefeng_aspnet/article/details/160182615

解决上述问题的算法非常简单。我们只需检查要移除的点是否属于凸包。如果是,则必须从初始集合中移除该点,然后重新构建凸包(参见上面凸包(分治))。

如果不是这样,那么我们已经有了解决方案(凸包不会改变)。

// C++ program to demonstrate delete operation
// on Convex Hull.
#include<bits/stdc++.h>
using namespace std;

// stores the center of polygon (It is made
// global because it is used in compare function)
pair<int, int> mid;

// determines the quadrant of a point
// (used in compare())
int quad(pair<int, int> 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
int orientation(pair<int, int> a, pair<int, int> b,
pair<int, int> 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
bool compare(pair<int, int> p1, pair<int, int> q1)
{
pair<int, int> p = make_pair(p1.first - mid.first,
p1.second - mid.second);
pair<int, int> q = make_pair(q1.first - mid.first,
q1.second - mid.second);

int one = quad(p);
int two = quad(q);

if (one != two)
return (one < two);
return (p.second*q.first < q.second*p.first);
}

// Finds upper tangent of two polygons 'a' and 'b'
// represented as two vectors.
vector<pair<int, int> > merger(vector<pair<int, int> > a,
vector<pair<int, int> > b)
{
// n1 -> number of points in polygon a
// n2 -> number of points in polygon b
int n1 = a.size(), n2 = b.size();

int ia = 0, ib = 0;
for (int i=1; i<n1; i++)
if (a[i].first > a[ia].first)
ia = i;

// ib -> leftmost point of b
for (int i=1; i<n2; i++)
if (b[i].first < b[ib].first)
ib=i;

// finding the upper tangent
int inda = ia, indb = ib;
bool done = 0;
while (!done)
{
done = 1;
while (orientation(b[indb], a[inda], a[(inda+1)%n1]) >=0)
inda = (inda + 1) % n1;

while (orientation(a[inda], b[indb], b[(n2+indb-1)%n2]) <=0)
{
indb = (n2+indb-1)%n2;
done = 0;
}
}

int uppera = inda, upperb = indb;
inda = ia, indb=ib;
done = 0;
int g = 0;
while (!done)//finding the lower tangent
{
done = 1;
while (orientation(a[inda], b[indb], b[(indb+1)%n2])>=0)
indb=(indb+1)%n2;

while (orientation(b[indb], a[inda], a[(n1+inda-1)%n1])<=0)
{
inda=(n1+inda-1)%n1;
done=0;
}
}

int lowera = inda, lowerb = indb;
vector<pair<int, int> > ret;

//ret contains the convex hull after merging the two convex hulls
//with the points sorted in anti-clockwise order
int ind = uppera;
ret.push_back(a[uppera]);
while (ind != lowera)
{
ind = (ind+1)%n1;
ret.push_back(a[ind]);
}

ind = lowerb;
ret.push_back(b[lowerb]);
while (ind != upperb)
{
ind = (ind+1)%n2;
ret.push_back(b[ind]);
}
return ret;

}

// Brute force algorithm to find convex hull for a set
// of less than 6 points
vector<pair<int, int> > bruteHull(vector<pair<int, int> > a)
{
// Take any pair of points from the set and check
// whether it is the edge of the convex hull or not.
// if all the remaining points are on the same side
// of the line then the line is the edge of convex
// hull otherwise not
set<pair<int, int> >s;

for (int i=0; i<a.size(); i++)
{
for (int j=i+1; j<a.size(); j++)
{
int x1 = a[i].first, x2 = a[j].first;
int y1 = a[i].second, y2 = a[j].second;

int a1 = y1-y2;
int b1 = x2-x1;
int c1 = x1*y2-y1*x2;
int pos = 0, neg = 0;
for (int k=0; k<a.size(); k++)
{
if (a1*a[k].first+b1*a[k].second+c1 <= 0)
neg++;
if (a1*a[k].first+b1*a[k].second+c1 >= 0)
pos++;
}
if (pos == a.size() || neg == a.size())
{
s.insert(a[i]);
s.insert(a[j]);
}
}
}

vector<pair<int, int> >ret;
for (auto e : s)
ret.push_back(e);

// Sorting the points in the anti-clockwise order
mid = {0, 0};
int n = ret.size();
for (int i=0; i<n; i++)
{
mid.first += ret[i].first;
mid.second += ret[i].second;
ret[i].first *= n;
ret[i].second *= n;
}
sort(ret.begin(), ret.end(), compare);
for (int i=0; i<n; i++)
ret[i] = make_pair(ret[i].first/n, ret[i].second/n);

return ret;
}

// Returns the convex hull for the given set of points
vector<pair<int, int>> findHull(vector<pair<int, int>> a)
{
// If the number of points is less than 6 then the
// function uses the brute algorithm to find the
// convex hull
if (a.size() <= 5)
return bruteHull(a);

// left contains the left half points
// right contains the right half points
vector<pair<int, int>>left, right;
for (int i=0; i<a.size()/2; i++)
left.push_back(a[i]);
for (int i=a.size()/2; i<a.size(); i++)
right.push_back(a[i]);

// convex hull for the left and right sets
vector<pair<int, int>>left_hull = findHull(left);
vector<pair<int, int>>right_hull = findHull(right);

// merging the convex hulls
return merger(left_hull, right_hull);
}

// Returns the convex hull for the given set of points after
// removing a point p.
vector<pair<int, int>> removePoint(vector<pair<int, int>> a,
vector<pair<int, int>> hull,
pair<int, int> p)
{
// checking whether the point is a part of the
// convex hull or not.
bool found = 0;
for (int i=0; i < hull.size() && !found; i++)
if (hull[i].first == p.first &&
hull[i].second == p.second)
found = 1;

// If point is not part of convex hull
if (found == 0)
return hull;

// if it is the part of the convex hull then
// we remove the point and again make the convex hull
// and if not, we print the same convex hull.
for (int i=0; i<a.size(); i++)
{
if (a[i].first==p.first && a[i].second==p.second)
{
a.erase(a.begin()+i);
break;
}
}

sort(a.begin(), a.end());
return findHull(a);
}

// Driver code
int main()
{
vector<pair<int, int> > a;
a.push_back(make_pair(0, 0));
a.push_back(make_pair(1, -4));
a.push_back(make_pair(-1, -5));
a.push_back(make_pair(-5, -3));
a.push_back(make_pair(-3, -1));
a.push_back(make_pair(-1, -3));
a.push_back(make_pair(-2, -2));
a.push_back(make_pair(-1, -1));
a.push_back(make_pair(-2, -1));
a.push_back(make_pair(-1, 1));

int n = a.size();

// sorting the set of points according
// to the x-coordinate
sort(a.begin(), a.end());
vector<pair<int, int> >hull = findHull(a);

cout << "Convex hull:\n";
for (auto e : hull)
cout << e.first << " "
<< e.second << endl;

pair<int, int> p = make_pair(-5, -3);
removePoint(a, hull, p);

cout << "\nModified Convex Hull:\n";
for (auto e:hull)
cout << e.first << " "
<< e.second << endl;

return 0;
}

输出:

凸包(convex hull):
-3 0
-1 -9
2 -6
5 3
2 5

时间复杂度:很容易看出,每次查询所花费的最大时间是构建凸包所需的时间,即 O(n*logn)。因此,总复杂度为 O(q*n*logn),其中 q 为要删除的点数。


辅助空间:O(n),因为占用了 n 个额外的空间。

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

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/28 1:27:27

3步掌握ZenTimings:AMD Ryzen内存监控的终极解决方案

3步掌握ZenTimings&#xff1a;AMD Ryzen内存监控的终极解决方案 【免费下载链接】ZenTimings 项目地址: https://gitcode.com/gh_mirrors/ze/ZenTimings 你是否曾因AMD Ryzen平台内存超频后系统不稳定而烦恼&#xff1f;或者想知道你的内存是否运行在最佳状态&#xf…

作者头像 李华
网站建设 2026/7/28 1:27:12

数据库行锁到底是什么?——从零讲到影院票务里的用法

&#x1f970;个人主页&#xff1a;会编程的土豆&#xff08;欢迎来访&#xff09; &#x1f48e;作者简介&#xff1a;后端学习者 ❄️个人专栏&#xff1a;数据结构与算法&#xff0c;数据库&#xff0c;leetcode ✨那些你一个人走过的夜路&#xff0c;终将化作照亮未来的光 …

作者头像 李华
网站建设 2026/7/28 1:26:49

WarcraftHelper:魔兽争霸III终极兼容性革命方案

WarcraftHelper&#xff1a;魔兽争霸III终极兼容性革命方案 【免费下载链接】WarcraftHelper Warcraft III Helper , support 1.20e, 1.24e, 1.26a, 1.27a, 1.27b 项目地址: https://gitcode.com/gh_mirrors/wa/WarcraftHelper 你是否曾因魔兽争霸III在现代系统上卡顿而…

作者头像 李华
网站建设 2026/7/28 1:25:32

收藏!告别模板套用,小白也能逆袭掌握大模型核心技术!

当前自学大模型者易陷入调用接口、套模板误区&#xff0c;难以满足企业对独立开发、解决问题人才的需求。文章强调应从底层逻辑学起&#xff0c;通过完整技术体系与实战项目&#xff0c;培养能解决真实业务问题的开发者。建议学习云和数据AI大模型应用开发课程&#xff0c;掌握…

作者头像 李华
网站建设 2026/7/28 1:22:43

Java增强型for循环原理与应用详解

1. Java增强型for循环的本质与语法规范Java的增强型for循环&#xff08;Enhanced for loop&#xff09;是J2SE 5.0引入的语法糖&#xff0c;专业术语称为"for-each循环"。其基本语法结构如下&#xff1a;for (ElementType element : collection) {// 处理element }这…

作者头像 李华