LK的旅行
时间限制:
2000 ms | 内存限制:
65535 KB
难度:
5
-
描述
-
LK最近要去某几个地方旅行,她从地图上计划了几个点,并且用笔点了出来,准备在五一假期去这几个城市旅行。现在希望你找出她点的所有的点中距离最远的两个点的距离是多少。各个景点可以认为是在一个平面上。
-
输入
- 第一行有一个整数0<n<10表示测试数据的组数随后的n组数据中,第一行有一个整数3<m<100000表示有m个旅游景点。随后的m行每行有两个整数,分别表示每一个点的x和y。景点坐标中可能有重复的,0<=x,y<=10000) 输出
- 每组数据输出距离最远的点对的距离的平方. 样例输入
-
1 4 0 0 1 1 0 1 1 0
样例输出
-
2
这是个的凸包问题,最远点对是凸包的某两个顶点,本来我是求完顶点集之后枚举。但是OJ给的m的数据量比较大,所以会超时O(N*2)。发现还要结合一个算法,即旋转卡壳法。
友情链接:
我觉得是讲的挺好的博客
凸包问题:http://www.cnblogs.com/jbelial/archive/2011/08/05/2128625.html
旋转卡壳法:http://blog.youkuaiyun.com/duanxian0621/article/details/8058009
#include <stdio.h>
#include <stdlib.h>
#define INF 999999
struct Node{
int x,y;
};
int count;
int Max(int a,int b,int c)
{
if(a<b)
a=b;
if(a<c)
a=c;
return a;
}
int com(const void *a,const void *b)
{//二级排序规则
Node *c;
Node *d;
c=(Node *)a;
d=(Node *)b;
if(c->x!=d->x)
return c->x-d->x;
return c->y-d->y;
}
Node p[100099];
Node v[100099];
int CountCrossProduct(int x1,int y1,int x0,int y0,int x2,int y2)
{//计算叉积
return (x1-x0)*(y2-y0)-(x2-x0)*(y1-y0);
}
int _CountCrossProduct(Node p1,Node p0,Node p2)
{//计算叉积的绝对值
int a=(p1.x-p0.x)*(p2.y-p0.y)-(p2.x-p0.x)*(p1.y-p0.y);
if(a>=0)
return a;
return -a;
}
int Graham()
{//Graham扫描法寻找凸包顶点
int top=0;//模拟栈
Node p0,p1,p2;
p[top++]=v[0];
p[top++]=v[1];
p[top++]=v[2];
for(int i=3;i<count;i++)
{
p2=v[i];
do
{
p1=p[--top];
p0=p[top-1];
}while(CountCrossProduct(p2.x,p2.y,p0.x,p0.y,p1.x,p1.y)>0);
p[top++]=p1;
p[top++]=p2;
}
return top;
}
int RCA(int m)
{//旋转卡壳法寻找凸包直径
int ans=0;
int i,j=1;
p[m]=p[0];
for(i=0;i<m;i++)
{
while(_CountCrossProduct(p[i],p[i+1],p[j+1])>_CountCrossProduct(p[i],p[i+1],p[j]))
j=(j+1)%m;
ans=Max(ans,(p[j].x-p[i].x)*(p[j].x-p[i].x)+(p[j].y-p[i].y)*(p[j].y-p[i].y),(p[j].x-p[i+1].x)*(p[j].x-p[i+1].x)+(p[j].y-p[i+1].y)*(p[j].y-p[i+1].y));
//更新最长距离
}
return ans;
}
int main()
{
int n;
int m;
int i;
scanf("%d",&n);
while(n--)
{
count=0;
scanf("%d",&m);
for(i=0;i<m;i++)
{scanf("%d%d",&p[i].x,&p[i].y);}
qsort(p,m,sizeof(Node),com);//按x由小到大,其次y由小到大排序
v[count++]=p[0];//p[0]为最左下的点
p[m].x=INF;p[m].y=INF;
//下面两个for循环实现以p0为原点,逆时针进栈
for(i=1;i<m;i++)//下半部分点按X从小往大进栈,相同x取y最小值
{
if(p[i].x==p[i-1].x)
continue;
if(p[i].y<p[0].y)
v[count++]=p[i];
}
for(i=m-1;i>=1;i--)//上半部分点按x从大往小进栈,相同x取y最大值
{
if(p[i].x==p[i+1].x)
continue;
if(p[i].y>p[0].y)
v[count++]=p[i];
}
m=Graham();
printf("%d\n",RCA(m));
}
return 0;
}