计算几何之旋转卡壳

大佬博客直通车

算法目的

根据凸包上的边的最远点随着边逆时针转动,一起逆时针转动的性质,使用计算几何的一些方法进行旋转遍历。

算法学习

例题1:二维平面上有若干个点,求该平面上最远的两个点的距离

首先,这两个点一定凸包上。
很容易想到个O(n2)的算法,暴力枚举凸包上的每两点即可,想想更好的算法。

一个我证明不来的定理:
距离某个点最远的点一定在距离某个点最远的边的两端点上
所以我们循环找距离每条边上最远的点,求两次dis(边上的端点)即可
我们发现,还是O(n2)

但是画图我们可以发现,随着逆时针取边,其边所对应的最远的点也在逆时针的旋转,这就可以实现O(n)的遍历了,但是求凸包还有个O(nlogn)的过程,所以总体时间复杂度是O(nlogn)

步骤

1.求凸包
2.循环遍历凸包上的每条边,找到其最远点,并求两次dis
如何找到最远点?
叉积!!!
对于s[i],s[i+1],p[j]形成的三角形,因为叉积正比于三角形面积,而底边s[i],s[i+1]固定不变,叉积越大三角形面积越大,三角形的高越大,点到直线s[i],s[i+1]的距离越远
循环判断下一个点是否比当前点更远,如果更远就再找下一个点,直到找到为止

代码如下(求凸包过程省略)

long long getdiameter(){
    
    
	if(cnt==2)return dis(s[1],s[2]);//仅有两个点
	long long ans=0;
	int j=3;
	for(int i=1;i<=cnt;i++){
    
    
		while(cross(s[i],s[i+1],s[j])<cross(s[i],s[i+1],s[j+1]))j=j%cnt+1;
		ans=max(ans,max(dis(s[i],s[j]),dis(s[i+1],s[j])));
	}
	return ans;
}

例题2:求最小矩阵覆盖

首先,覆盖所有点等价于覆盖凸包点
其次,目标矩阵的某一条边一定与凸包上的一条边共线

循环遍历边找以这些边作为矩阵的底边矩阵的上左右边即可

扫描二维码关注公众号,回复: 13121314 查看本文章

如何找上边?
上边就是最远点所在的平行边,旋转卡壳找即可

如何找左右边?
左边就是以该底边为x轴的最左边点所在的垂直边,可以用点积判角度找
同样的,底边逆时针转动,其对应的最左边的点也在逆时针转动
也用旋转卡壳找即可
步骤:用点积判断两个向量角度,从而判断下一个是否比当前点更靠左,如果更靠左,就再找下一个点,直到找到最做点为止

猜你喜欢

转载自blog.csdn.net/weixin_43602607/article/details/114198866