当前位置: 首页 > news >正文

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 个额外的空间。

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

http://www.jsqmd.com/news/1277669/

相关文章:

  • League Akari:英雄联盟玩家的终极效率工具
  • 【通义千问私有化部署终极 checklist】:NVIDIA A10/A800/H20适配清单、国产信创环境兼容矩阵、安全审计必检项(含等保2.0合规对照表)
  • (2026最新)大同本地人必选的靠谱漏水检测维修推荐:正规防水补漏防水-卫生间/厨房/屋顶/阳台/外墙渗漏水精准测漏,本地人的信赖之选 - 安佳防水
  • 从零理解强化学习:核心概念、算法演进与PPO、DQN等实战入门
  • Claude模型选择指南:Opus、Sonnet、Haiku的成本效益与场景化应用
  • 星火应用商店:Linux桌面软件生态的革命性解决方案 [特殊字符]
  • Niagara—— 渲染器详解
  • 为什么你的百度网盘解析总失效?揭秘安全不限速的底层逻辑
  • Python学习误区与高效方法
  • League Akari:英雄联盟玩家必备的终极本地化效率工具
  • 基于Apache Doris一站式构建知识图谱增强RAG系统
  • 全球高分辨率降水估计数据集(静止轨道 (GEO) 卫星观测数据)
  • 当Vibe Coding遇上熵增定律:速度红利背后的系统性债务与破局路径
  • 2026 年新发布:金坛值得关注的宣传片拍摄公司工作室哪家好,拍出爆款:揭秘顶级宣传片背后的秘密 - 企业推荐官【认证官方】
  • 人类驾驶与端到端自动驾驶的认知差异解析
  • 【C++】map 与 multimap
  • Go语言实现二进制回文数统计与优化
  • 21天前端面试系统化备战:从基础到高级实战进阶指南
  • 终极指南:如何在Mac上使用QMCDecode免费解锁QQ音乐加密格式,实现音乐自由播放?
  • Kimi API调用成本飙升?(真实账单分析+3层降本方案)——某金融科技团队月省¥23,800实录
  • Python与其他编程语言的对比与应用场景分析
  • 在Windows 10和11上完美运行Android应用:WSABuilds完整指南
  • 如何快速解密QMC音乐:完整技术指南与音频格式转换解决方案
  • 5分钟免费解锁:applera1n iOS激活锁终极绕过工具完整指南
  • 如何通过无线或数据线将文件从 iPhone 传输到 PC?
  • 2026年AI报表软件测评:智能与兼容性解析 - 科技焦点
  • GIS在线局部放电监测系统深度研究报告
  • 如何高效批量下载B站视频?Bilidown终极指南帮你三步搞定
  • 千笔AI:深度学习驱动的学术写作智能辅助平台
  • Logseq终极指南:从零开始打造你的个人知识库,5分钟快速上手隐私优先的知识管理平台