Andrew算法(我确实不懂Graham)

先解释一下:这两个算法分别都是凸包问题的算法,然后Andrew是Graham的变种,速度更快,更稳定,非常优秀,介于我已经把Graham写的莫名其妙的WA了,所以我选择了这种算法!

我认为在这里,还是有必要向大家在这里先普及一下什么是凸包:


计算几何凸包

凸包:给你n个散落的点,让你求出最小的凸多边形将所有的点包括起来,或者点在边上。用到的算法是Graham或Andrew!

这里给一个链接:
Graham算法详解

下面给出Andrew算法的思路

First

首先先按照x坐标大小或y坐标大小进行排序(如果x坐标一样,y坐标就从小到大排序如果y坐标一样那么x坐标就从小到大排序)

Second

然后进入程序的主干部分,先说一下Andrew主干的大体思路,我们分两次来求这个凸包,先从左到右一遍,再从右到左一遍(或先从下到上一遍,再从上到下一遍)首先我们一定要明白第n-1个点一定会在第一遍时进入凸包栈内(看了上面链接的朋友都应该知道这个栈是如何操作的,这里不再赘述)(因为n个点是从0n-1),所以第二遍的时候不必从n-1开始,从n-20开始就可以了(代码上会有体现)然后就完了!

现在我们来详细讲一下如何实现Second的操作

我们要实现找凸包,那么就必须找到最外层的点,这里就要使用叉积进行判断(向量a叉向量b=a.x×b.y-b.x×a.y)如果为正a在b的右边反之在左边(题目中因为我们只能定义一个基准坐标系,所以为了实现这个功能我们就必须找参照点,参照点作为临时原点)代码中xmult会体现。

然后就差不多了!

下面就是代码了:

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
struct point{
	int x,y;
};
bool cmp(point a,point b)
{
	if(a.y==b.y&&a.x<b.x)
	return true;
	else if(a.y<b.y) return true;
	return false;
}
double dis(point a,point b)
{
	return sqrt((a.x-b.x)*(a.x-b.x)+(b.y-a.y)*(b.y-a.y));
}
bool xcross(point a,point b,point c)
{
	return (a.x-c.x)*(b.y-c.y)>=(b.x-c.x)*(a.y-c.y);
}
point node[100005];
int num[100005];
int n;
int main()
{
	scanf("%d",&n);
	for(int i=0;i<n;++i)
	{
		scanf("%d%d",&node[i].x,&node[i].y);
	}
	sort(node,node+n,cmp);
	num[0]=0; num[1]=1;
	int top=1;
	for(int i=2;i<n;++i)
	{
		while(top>1&&xcross(node[i],node[num[top]],node[num[top-1]]))
		top--;
		top++;
		num[top]=i;
	}
	int basic=top;
	for(int i=n-2;i>=0;--i)
	{
		while(top>basic&&xcross(node[i],node[num[top]],node[num[top-1]]))
		top--;
		top++;
		num[top]=i;
	}
	double s;
	s=0.0;
	for(int i=1;i<=top;++i)
	{
		s+=dis(node[num[i-1]],node[num[i]]);
	}
	printf("%.1lf",s);
	return 0;
}

希望以后能够明白它的father——Gramham算法是怎么写的!

原文地址:https://www.cnblogs.com/mudrobot/p/13330937.html