旋转卡壳 学习笔记
板子题
Luogu P1452 && POJ2187 && [USACO03FALL] Beauty Contest G
传送门toLuogu 传送门toPOJ
在平面上给出一些点,求出最远点的距离的平方。
题目解析
显然最远点在能围住这些点的最小凸包上,所以我们先求出凸包,就转化成求凸包的直径问题。
算法解析
算法名字叫旋转卡壳,其实还是挺形象的,其实就是一对平行线卡着凸包旋转。
我们先选定一条边,找出在这个凸包里面最远的点(找一对平行线刚好能卡住这个凸包);然后顺时针旋转这对平行线,我们发现,这对平行线夹住凸包的一条边和一个顶点都是在逆时针旋转,这样就可以做到 。
放一张图演示一下。(网上扒的)
然后就是代码了
#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; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具