旋转卡壳 学习笔记

板子题

Luogu P1452 && POJ2187 && [USACO03FALL] Beauty Contest G
传送门toLuogu 传送门toPOJ
在平面上给出一些点,求出最远点的距离的平方。

题目解析

显然最远点在能围住这些点的最小凸包上,所以我们先求出凸包,就转化成求凸包的直径问题。

算法解析

算法名字叫旋转卡壳,其实还是挺形象的,其实就是一对平行线卡着凸包旋转。
我们先选定一条边,找出在这个凸包里面最远的点(找一对平行线刚好能卡住这个凸包);然后顺时针旋转这对平行线,我们发现,这对平行线夹住凸包的一条边和一个顶点都是在逆时针旋转,这样就可以做到 \(\Theta\left(n\right)\)
放一张图演示一下。(网上扒的)

然后就是代码了

#include<cmath>
#include<cstdio>
#include<algorithm>
#define I inline
#define db double
#define U unsigned
#define R register
#define ll long long
#define RI register int
#define ull unsigned long long
#define abs(x) ((x)>0?(x):(-(x)))
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define Me(a,b) memset(a,b,sizeof(a))
#define EPS (1e-7)
#define INF (0x7fffffff)
#define LL_INF (0x7fffffffffffffff)
#define maxn 50039
//#define debug
using namespace std;
#define Type int
I Type read(){
	Type sum=0; int flag=0; char c=getchar();
	while((c<'0'||c>'9')&&c!='-') c=getchar(); if(c=='-') c=getchar(),flag=1;
	while('0'<=c&&c<='9'){ sum=(sum<<1)+(sum<<3)+(c^48); c=getchar(); }
	if(flag) return -sum; return sum;
}
struct Vector{
	int x,y;
	Vector operator + (const Vector &x) const{ return (Vector){this->x+x.x,this->y+x.y}; }
	Vector operator - (const Vector &x) const{ return (Vector){this->x-x.x,this->y-x.y}; }
	double operator * (const Vector &x) const{ return this->x*x.y - this->y*x.x;  }
	bool operator < (const Vector &x) const { if(this->y==x.y) return this->x < x.x;
		return this->y < x.y; }
}a[maxn];
int n,minx;
struct Stack{
	int data[maxn],_top;
	int top(){ return data[_top]; }
	void push(int x){ data[++_top]=x; return; }
	void pop(){ _top--; return; }
	void clear(){ _top=0; return; }
}s;
I int dis(Vector x,Vector y){ return (x.x-y.x)*(x.x-y.x)+(x.y-y.y)*(x.y-y.y); }
I void swap(Vector &a,Vector &b){ Vector tmp=a; a=b; b=tmp; return; } 
I Vector get(Vector x,Vector y){ return y-x; } 
I int cmp(Vector x,Vector y){
	if(get(a[1],x)*get(a[1],y)==0) return dis(a[1],x) < dis(a[1],y);
	return get(a[1],x)*get(a[1],y)>0;
}
int getdis(Vector P,Vector A,Vector B){
	return (get(P,A)*get(P,B))*(get(P,A)*get(P,B))/dis(A,B); }
int main(){
	//freopen("P1452_4.in","r",stdin);
    //freopen(".out","w",stdout);
	n=read(); RI i,j; for(i=1;i<=n;i++) scanf("%d%d",&a[i].x,&a[i].y);
	minx=1; for(i=2;i<=n;i++) if(a[i]<a[minx]) minx=i; if(minx!=1) swap(a[1],a[minx]);
	sort(a+2,a+n+1,cmp); s.clear(); s.push(1); s.push(2);
	for(i=3;i<=n;i++){
		while(get(a[s.data[s._top-1]],a[s.top()])*get(a[s.top()],a[i])<=0 && s._top>=2)
			s.pop();
		s.push(i); }
	i=1,j=3; int ans=0;
	if(s._top==2){ printf("%d",dis(a[s.data[1]],a[s.data[2]])); return 0; }
	if(s._top==3){
		printf("%d",max(max(dis(a[s.data[1]],a[s.data[2]]),dis(a[s.data[1]],a[s.data[3]]))
			,dis(a[s.data[2]],a[s.data[3]]))); return 0; }
	for(i=1;i<=s._top;i++){
		while(getdis(a[s.data[j]],a[s.data[i]],a[s.data[i+1]])<=
		getdis(a[s.data[j%s._top+1]],a[s.data[i]],a[s.data[i+1]])) j=j%s._top+1;
		ans=max(ans,max(dis(a[s.data[j]],a[s.data[i]]),dis(a[s.data[j]],a[s.data[i+1]])));
	}
	printf("%d",ans);
	return 0;
}
posted @ 2021-10-07 14:09  jiangtaizhe001  阅读(48)  评论(0编辑  收藏  举报