旋转卡壳 学习笔记

板子题

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

题目解析

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

算法解析

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

然后就是代码了

#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 @   jiangtaizhe001  阅读(58)  评论(0编辑  收藏  举报
编辑推荐:
· 开发者必知的日志记录最佳实践
· 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工具
点击右上角即可分享
微信分享提示