描述
给出平面上n个点的坐标,计算最远两点间的距离,以及包含所有点的最小凸多边形(凸包)
输入
第一行一个整数n,接下来是n行的实数对,表示n个点坐标。2<=n<=10000
n
x1 y1
x2 y2
…
xn yn
输出
输出2行,第一行是最远两点间的距离,结果保留四位小数。第二行是从P0开始,逆时针输出凸包的顶点号。
顶点号为0到n-1,由点的输入次序决定。
P0点表示最下方的点号,如果有多个点并列最下方,则P0为其中最左边的点号。
输入样例 1
9
200 400
300 400
300 300
400 300
400 400
500 400
500 200
350 200
200 200
输出样例 1
360.5551
8 6 5 0
这里用于sort排序的数组ord[],用的很巧妙。
凸包形成过程如下图:
#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#define eps 1e-8
using namespace std;
typedef struct
{
double x, y;
} point;
point p[10005];
//用于排序的标号,并保存输入时的顺序标号
int ord[10005];
int n;
//stack用于保存最小凸包的顶点序号
int stack[10005];
double dist(point a,point b){
return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
int check(point a,point b,point c){
double k;
k = a.x*b.y-a.y*b.x+b.x*c.y-b.y*c.x+c.x*a.y-c.y*a.x;
if(k>eps)
return 1;
else if(k<-eps)
return -1;
else
return 0;
}
bool cmp(int a,int b){//排序依据
int i;
i=check(p[ord[0]],p[a],p[b]);
if(i==0) return(dist(p[ord[0]],p[a])<dist(p[ord[0]],p[b]));
else return i>0;
}
int main()
{
cin >> n;
int i, j,temp;
for (i = 0; i < n;i++){
cin >> p[i].x >> p[i].y;
ord[i] = i;
}
int k = 0;
for (i = 1; i < n;i++){
if(p[i].y<p[k].y || (p[i].y==p[k].y && p[i].x<p[k].x))
k = i;
}
swap(ord[0], ord[k]);
//将所有点按与水平面夹角大小排序
sort(ord + 1, ord + n, cmp);
stack[0] = ord[0];
int top=0;
for (i = 1; i < n;i++){
/*当点p[ord[i]]在线p[stack[top-1]],p[stack[top]]的右边时,链接不构成凸包.
所以舍去栈顶的点p[stack[top]],换成点p[ord[i]]。 */
while(top>0 && check(p[stack[top-1]],p[stack[top]],p[ord[i]])<=0) top--;
stack[++top] = ord[i];
}
double ans;
for (i = 0; i <= top;i++){//求最长两点距离
for (j = i + 1; j <= top;j++){
ans = max(dist(p[stack[i]], p[stack[j]]),ans);
}
}
printf("%.4lf\n", ans);
for (i = 0; i <= top; i++)
cout << stack[i] << " ";
return 0;
}