凸包模板讲解

Andrew算法

Andrew算法是Graham算法的变种。
其主要思想为把凸包上的点依次放入栈中,
如果发现形成了凹多边形(叉积为负值)
就删除一些点,使得又能够维持凸的形态。
这时就会发现,处理各个点需要按照x从左往右的顺序,排序即可
当然,这只是处理了下凸的一个凸壳,倒过来再刷一次,就得到了整个凸包

处理方向顺序

处理壳的方向为下半壳从左到右,上半壳从右到左。

步骤

1、先把点排序 x从小到大,x相等y从小到大

2、先把第一个点和第二个点加入栈中,然后从第三个开始一直到第N个点进行下半凸壳判断

3、当处理下半凸壳(逆时针从左到右)的时候:


         b
       /   \
x --- a     c --- y

这个a->b->c 凹进去了,数学上可以表示为a,b的斜率大于b,c的斜率,所以遇到这种情况,就把凹进去的点b去掉就行了

4、先把第N-1个点加入栈中,然后从第N-2个点开始进行上半凸壳判断

5、处理上半凸壳(逆时针从右到左)的时候:

x --- a       c --- y
        \   /
          b

这个c->b->a 凹进去了,数学上可以表示为c,b的斜率大于b,a的斜率,所以遇到这种情况,就把凹进去的点b去掉就行了

6、最后看一下加进去点的个数,如果全部点都加进去了说明没有凹点,是凸包

代码(模板)

#include <bits/stdc++.h>
using namespace std;
const int N = 305;           //最多有多少个点


struct Point
{
	double x, y;
	Point() {}
	Point(double xx, double yy) : x(xx), y(yy) {}
	bool operator<(const Point &a) const //按照x从小到大排序,x相同按照y从小到大排序
	{
		if (x == a.x)
			return y < a.y;
		return x < a.x;
	}
	Point operator-(const Point a) const //重载减号,使两个点直接相减
	{
		return Point(x - a.x, y - a.y);
	}
} p[N], st[N]; //p是点,st是栈


bool check(Point a, Point b)
{
	return a.x * b.y <= b.x * a.y;
} //检查斜率


bool judge(int n)
{
	sort(p + 1, p + n + 1);
	int head = 0;
	//凸包下半边
	for (int i = 1; i <= n; ++i)
	{
		//除去栈里面下半凸壳的凹点
		while (head > 1 && check(st[head] - st[head - 1], p[i] - st[head])) //保证栈里至少有两个元素才能进行斜率比较
			head--;
		st[++head] = p[i];
	}
	int tmp = head;
	//凸包上半边
	for (int i = n - 1; i >= 1; --i) //起点一定要加进去,为了把栈里面不符合的点除去,然后最后结果减1即可
	{
		//除去栈里面上半凸壳的凹点
		while (head > tmp && check(st[head] - st[head - 1], p[i] - st[head])) //保证栈里至少有两个元素才能进行斜率比较
			head--;
		st[++head] = p[i];
	}
	return head - 1 == n;
}


int main()
{
	int n;         //n个点
	while (cin >> n)
	{
		for (int i = 1; i <= n; ++i)
			cin >> p[i].x >> p[i].y;      //输入n个点的坐标
		if (judge(n))                     //如果所有的点都在栈里,说明这些点组成的图形是个凸包
			cout << "it is a Convex Hull" << endl;
		else                              //否则不是凸包
			cout << "it is not a Convex Hull" << endl;
		
		//最后栈里面的元素就是组成凸包的点
	}
	return 0;
}
  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值