HDU 1392 Surround the Trees(凸包)

来源:互联网 发布:手机淘宝旧版本 编辑:程序博客网 时间:2024/05/18 09:03

Problem Description

There are a lot of trees in an area. A peasant wants to buy a rope to surround all these trees. So at first he must know the minimal required length of the rope. However, he does not know how to calculate it. Can you help him?
The diameter and length of the trees are omitted, which means a tree can be seen as a point. The thickness of the rope is also omitted which means a rope can be seen as a line.

There are no more than 100 trees.

Input

The input contains one or more data sets. At first line of each input data set is number of trees in this data set, it is followed by series of coordinates of the trees. Each coordinate is a positive integer pair, and each integer is less than 32767. Each pair is separated by blank.

Zero at line for number of trees terminates the input for your program.

Output

The minimal length of the rope. The precision should be 10^-2.

Sample Input

9
12 7
24 9
30 5
41 9
80 7
50 87
22 9
45 1
50 7
0

Sample Output

243.06

Source

Asia 1997, Shanghai (Mainland China)

Recommend

Ignatius.L | We have carefully selected several similar problems for you: 1115 1086 2108 2036 2150

题意:给n个点,求其凸包边长

凸包:给定二维平面上的点集,凸包就是将最外层的点连接起来构成的凸多边型,它能包含点集中所有的点。
这里写图片描述

解决:在所有点中选取y坐标最小的一点H,当作基点。如果存在多个点的y坐标都为最小值,则选取x坐标最小的一点。坐标相同的点应排除。然后按照其它各点p和基点构成的向量<H,p>;与x轴的夹角进行排序,夹角由大至小进行顺时针扫描,反之则进行逆时针扫描。实现中无需求得夹角,只需根据余弦定理求出向量夹角的余弦值即可。以上图为例,基点为H,根据夹角由小至大排序后依次为H,KCD,L,F,G,EI,B,A,J。下面进行逆时针扫描。
#include<iostream>#include <cstdio>  #include <cmath>  #include <cstdlib>  #include <algorithm>  #define eps 1e-8  #define MAXN 110  using namespace std;struct Point{    double x, y;    Point() {}    Point(double X, double Y)     {        x = X; y = Y;    }};Point P[MAXN];int dcmp(double x){    if (fabs(x) < eps)        return 0;    else        return x < 0 ? -1 : 1;}Point operator - (Point A, Point B) {    return Point(A.x - B.x, A.y - B.y);}Point operator + (Point A, Point B) {    return Point(A.x + B.x, A.y + B.y);}Point operator * (Point A, double p) {    return Point(A.x*p, A.y*p);;}double Cross(Point A, Point B) {    return A.x*B.y - A.y*B.x;}double Dot(Point A, Point B) {    return A.x*B.x + A.y*B.y;}double Dis(Point A, Point B) {    return sqrt((A.x - B.x)*(A.x - B.x) + (A.y - B.y)*(A.y - B.y));}bool operator == (Point A, Point B) {    return dcmp(A.x - B.x) == 0 && dcmp(A.y - B.y) == 0;}bool cmp(Point A, Point B)//极角排序 按极角排序,若角度相等距离大的在前面  {    double temp = Cross(A - P[0], B - P[0]);    if (dcmp(temp) > 0) return true;    if (dcmp(temp) == 0 && dcmp(Dis(P[0], A) - Dis(P[0], B)) < 0) return true;    return false;}int Stack[MAXN], top;void input(int n){    scanf("%lf%lf", &P[0].x, &P[0].y);    double xx = P[0].x, yy = P[0].y;    int id = 0;    for (int i = 1; i < n; i++)    {        scanf("%lf%lf", &P[i].x, &P[i].y);        if (P[i].y < yy || (P[i].y == yy && P[i].x < xx))        {            xx = P[i].x;            yy = P[i].y;            id = i;        }    }    Point T;    T = P[0]; P[0] = P[id]; P[id] = T;    sort(P + 1, P + n, cmp);//极角排序  }void Graham(int n){    if (n == 1) { top = 0; Stack[0] = 0; }    else if (n == 2)    {        top = 1;        Stack[0] = 0;        Stack[1] = 1;    }    else    {        for (int i = 0; i <= 1; i++)            Stack[i] = i;        top = 1;        for (int i = 2; i < n; i++)        {            while (top > 0 && dcmp(Cross(P[Stack[top]] - P[Stack[top - 1]], P[i] - P[Stack[top - 1]])) <= 0)                 top--;            top++;            Stack[top] = i;        }    }}int main(){    int n;    while (scanf("%d", &n), n)    {        input(n);        Graham(n);        double ans = 0;        for (int i = 0; i < top; i++)            ans += Dis(P[Stack[i]], P[Stack[i + 1]]);        if (top > 1)            ans += Dis(P[Stack[top]], P[Stack[0]]);        printf("%.2lf\n", ans);    }    return 0;}
原创粉丝点击