Time Limit: 3000MS | Memory Limit: 65536K | |
Total Submissions: 25256 | Accepted: 7756 |
Description
Input
Output
Sample Input
4 0 0 0 1 1 1 1 0
Sample Output
2
题意:给n个点的坐标,计算这些点两两距离最大的那个距离;
思路:如果直接枚举,肯定超。所以可以先形成凸包,距离最大的那两个端点一定是凸包中的点。所以形成凸包后再枚举就可以了。
这里用了graham算法,
1 #include<stdio.h> 2 #include<string.h> 3 #include<math.h> 4 #include<algorithm> 5 using namespace std; 6 const int maxn = 50010; 7 int top,stack[maxn]; 8 int n; 9 struct Point 10 { 11 double x; 12 double y; 13 } point[maxn]; 14 15 double cross(const Point &a, const Point &b, const Point &c)//三个点的叉积,结果大于0说明bc的极角大于ac的极角,等于0说明共线; 16 { 17 return (a.x-c.x)*(b.y-c.y) - (a.y-c.y)*(b.x-c.x); 18 } 19 20 double dis(const Point &a, const Point &b) 21 { 22 return (a.x-b.x)*(a.x-b.x) + (a.y-b.y)*(a.y-b.y); 23 } 24 25 int cmp(const Point &a, const Point &b)//对点排序找出最左最下的那个点作为point[0]; 26 { 27 if(a.y == b.y) 28 return a.x < b.x; 29 return a.y < b.y; 30 } 31 32 void Graham() 33 { 34 sort(point,point+n,cmp); 35 for(int i = 0; i <= 2; i++) 36 stack[i] = i; 37 top = 1; 38 for(int i = 2; i < n; i++) 39 { 40 while(top && cross(point[i],point[stack[top]],point[stack[top-1]]) >= 0) 41 top--; 42 stack[++top] = i; 43 } 44 int count = top; 45 stack[++top] = n-2; 46 for(int i = n-3; i >= 0; i--) 47 { 48 while(top != count && cross(point[i],point[stack[top]],point[stack[top-1]])>=0) 49 top--; 50 stack[++top] = i; 51 } 52 } 53 54 int main() 55 { 56 while(~scanf("%d",&n)) 57 { 58 for(int i = 0; i < n; i++) 59 scanf("%lf %lf",&point[i].x,&point[i].y); 60 61 Graham(); 62 63 double ans = 0,distance; 64 for(int i = 0; i < top; i++) 65 { 66 for(int j = 0; j < i; j++) 67 { 68 distance = dis(point[stack[i]],point[stack[j]]); 69 if(ans < distance) 70 ans = distance; 71 } 72 } 73 printf("%.0lf\n",ans); 74 } 75 return 0; 76 }
这是经典的计算几何学问题,判断向量p1=(x1,y1)到p2=(x2,y2)是否做左转,只需要判断x1*y2-x2*y1的正负,如果结果为正,则从p1到p2做左转。也就是向量的叉积。
Graham算法是这样的
1.将各点排序(),为保证形成圈,把P0在次放在点表的尾部;
2.准备堆栈:建立堆栈S,栈指针设为t,将0、1、2三个点压入堆栈S;
3.对于下一个点i
只要S[t-1]、S[t]、i不做左转
就反复退栈;
将i压入堆栈S
4.堆栈中的点即为所求凸包;