POJ 2187 Beauty Contest | 旋转卡壳
题目:
给n个点,输出距离最远的一对点的距离的平方
题解:
旋转卡壳模板!
首先可以肯定的是最远的点一定是凸包的一对顶点!(这个正确性是很显然的)
所以我们枚举每个顶点所在的边,将它平移,平移到经过的最远一个点就是含有这个点的最远距离
所以N2是可以解决的!
但是这个和枚举点是没区别的.
但是如果我们逆时针枚举边的话,最远点变化也是逆时针的,所以接着上次的算就好啦.这样就优化到O(n)
具体实现的话可以叉积用面积算
#include<cstdio> #include<algorithm> #include<cstring> #define N 50005 using namespace std; int n,m; void chkmax(int &a,const int &b) { if (a<b) a=b; } struct point { int x,y; point () {}; point (int _x,int _y) { x=_x,y=_y; } point operator - (const point &a) const { return point(x-a.x,y-a.y); } int operator * (const point &a)const { return x*a.y-y*a.x; } int norm() const { return x*x+y*y; } }p[N],q[N]; bool cmp(int u,int v) { int det=(p[u]-p[1])*(p[v]-p[1]); if (det!=0) return det>0; return (p[u]-p[1]).norm()<(p[v]-p[1]).norm(); } void Graham() { int id=1; for (int i=2;i<=n;i++) if (p[i].x<p[id].x || (p[i].x==p[id].x && p[i].y<p[id].y)) id=i; if (id!=1) swap(p[1],p[id]); int per[N]; for (int i=1;i<=n;i++) per[i]=i; sort(per+2,per+1+n,cmp); q[++m]=p[1]; for (int i=2;i<=n;i++) { int j=per[i]; while (m>=2 && (p[j]-q[m-1])*(q[m]-q[m-1])>=0) m--; q[++m]=p[j]; } } int Area(const point &x,const point &y,const point &z) { return (y-x)*(z-x); } int nxt(int x) { return x==m?1:x+1; } int solve() { if (m==2) return (q[2]-q[1]).norm(); int res=0; q[m+1]=q[1]; for (int i=1,j=3;i<=m;i++) { while (nxt(j)!=i && Area(q[i],q[i+1],q[j])<=Area(q[i],q[i+1],q[j+1])) j=nxt(j); chkmax(res,(q[j]-q[i]).norm()); chkmax(res,(q[j]-q[i+1]).norm()); } return res; } int main() { scanf("%d",&n); for (int i=1;i<=n;i++) scanf("%d%d",&p[i].x,&p[i].y); Graham(); printf("%d\n",solve()); return 0; }