Loading

【理论】二维凸包求法

本文仅介绍 Andrew 算法。

考虑一个凸包的本质是什么?是由一个上凸壳和下凸壳组合形成的多边形

你说的对,但是上凸壳和下凸壳的本质又是什么?

是一堆斜率单调的直线。

凸包求法似乎呼之欲出了。

我们要采取增量法,所以我们需要有一个加入点并动态维护之的顺序,我们先将所有点按 \(x\) 坐标排序。

紧接着,以下凸壳为例,我们维护一个栈(某种意义上,可以看做单调栈),栈内放着我们目前维护的下凸壳内的所有点,按 \(x\) 坐标的顺序每次加入一个新点作为增量,如何判定该点对下凸壳的影响?将栈顶和该点分别与栈顶下第一点连线,比较两者斜率的大小,若前者更大(建议画图理解),则为了保持斜率的单调性(该点作为增量必须加入),需要将栈顶弹出,如此操作直到栈顶无需弹出或栈的大小为 \(1\) 时,将该点入栈。

上凸壳亦然,不过加入新点作为增量要按照 \(x\) 坐标的逆序进行。

最终凸包\(=\)上凸壳\(\cup\)下凸壳。

代码
//Andrew
ll n,s[100005],top;
double ans;
int main(){
	rd(n);
	rep(i,1,n) cin>>a[i].x>>a[i].y;
	sort(a+1,a+n+1,cmp);
	s[top=1]=1;
	rep(i,2,n){
		do{
			if(top<2) break;
			if(slope(s[top-1],s[top])>slope(s[top-1],i)) --top;
			else break;
		}while(1);
		s[++top]=i;
	}
	while(top>1){
		ans+=dis(s[top],s[top-1]);
		--top;
	}
	s[top=1]=n;
	repp(i,n-1,1){
		do{
			if(top<2) break;
			if(slope(s[top-1],s[top])>slope(s[top-1],i)) --top;
			else break;
		}while(1);
		s[++top]=i;
	}
	while(top>1){
		ans+=dis(s[top],s[top-1]);
		--top;
	}
	printf("%.2lf",ans);
}
posted @ 2023-03-08 16:08  lstqwq  阅读(45)  评论(0编辑  收藏  举报