首页 > 代码库 > geometry2187
geometry2187
给定平面上的一些散点集,求最远两点距离的平方值。
平面上的散点集的最远的两点距离必然在这个散点集的凸包的某两个顶点上出现。
之后枚举凸包所有的点对,找出最大的即可。
如果用旋转卡壳,那么速度比较快。
旋转卡壳可以用于求凸包的直径、宽度,两个不相交凸包间的最大距离和最小距离
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define N 50005
using namespace std;
struct point
{
int x,y;
}p[N];
int top,n,s[N];
int cross(point a,point b,point c)//叉积
{
return (b.x - a.x) * (c.y - a.y) - (c.x - a.x) * (b.y - a.y);
}
int dis(point a,point b)//距离
{
return (a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y);
}
bool cmp(point a,point b)
{
int ans = cross(p[0],a,b);//大于0,则a比b极坐标角度小
if( ans > 0 || (ans == 0 && dis(p[0],a) > dis(p[0],b) )) return true;
return false;
}
void graham()//凸包模板。。
{
s[0] = 0;
s[1] = 1;
top = 1;
for(int i = 2;i != n ;i ++)
{
while(top && cross(p[s[top - 1]],p[s[top]],p[i] ) < 0) top--;
s[++top] = i;
}
top ++;
}
void RC()//旋转卡壳
{
int q,p1,pp,qq,rr,r,ans = 0;
q = 1;//从1开始
ans = dis(p[s[0]],p[s[1]]);
for(int i = 0; i != top ;i ++)
{
while(abs(cross(p[s[(i+1)%top]],p[s[i%top]],p[s[(q+1)%top]])) >
abs(cross(p[s[(i+1)%top]],p[s[i%top]],p[s[q%top]])))
q = (q + 1)%top;
/*
点对a,c距离最大,即该点构成的边(a,b)与点c构成的三角形(对应向量构成的平行四边形面积最大),之后(a,c)(b,c)取更大的即可
用cross不仅仅可以用来计算向左偏,还是向右偏。同时还
可以表示三点构成的平行四边形面积,距离某边最大的点
一定是与该边构成的平行四边形面积最大的点。同时遍历所
有点的时候,面积是一个单峰函数,先变大后变小。
这里起始时i=0,求的三个点是1,0,2与1,0,1进行比较,因为有可能与0最远的点就是1,如果直接从1,0,2,与1,0,3,进行比较,就会没考虑(0,1)是最远距离的可能性*/
ans = max(ans , max(dis(p[s[(i+1)%top]],p[s[q]]),dis(p[s[i%top]],p[s[q]])));
}
printf("%d\n",ans);
}
int main()
{
while(~scanf("%d",&n))
{
for(int i =0 ;i != n;i ++) scanf("%d%d",&p[i].x,&p[i].y);
int u = 0;
for(int i = 1;i != n;i ++)//寻找基点
{
if(p[u].y > p[i].y || (p[u].y == p[i].y && p[u].x > p[i].x)) u = i;
}
if(u)
{
swap(p[u].y,p[0].y);
swap(p[u].x,p[0].x);
}
sort(p + 1,p + n,cmp);
graham();
RC();
}
return 0;
}
geometry2187