HD 1392 Surround the Trees 解題報告

Surround the Trees

Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 6231 Accepted Submission(s): 2339


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
解題分析:
此題爲典型的求凸包問題,題意爲,此地有n棵樹,農場主要用最短的繩子圍住所有樹,讓你計算最少需要繩子的長度。題目要注意只有一個點的情況,還有隻有兩個點的情況。
解題代碼:
#include <iostream>
#include <cmath>
#include <algorithm>
#include <stdio.h>
/***這是一個求凸包的模板***/
using namespace std;
const int MAXN = 100;
const double eps = 1e-8;
struct Point
{
    int x;
    int y;
};
struct Point p[MAXN]; // 保存輸入結點
struct Point st[MAXN];  // 保存凸包結點,把que當一個棧來使用
int top;          // 記錄棧頂位置
double dis(Point a, Point b)// 求a, b兩點距離
{
    return sqrt(double((a.x-b.x)*(a.x-b.x) + (a.y-b.y)*(a.y-b.y)));
}
int cross(Point p1,Point p2, Point p0)// 求P0P1與P0P2的叉積
{
    return (p1.x-p0.x)*(p2.y-p0.y)-(p2.x-p0.x)*(p1.y-p0.y);
}
bool cmp(Point p1,Point p2)
{
    int k = cross(p2,p1,p[0]); //p0p2叉乘p0p1
    if(k<0||(!k&&dis(p1,p[0])-dis(p2,p[0])>eps))//p1的極角比p2小或者極角相等去距離大的
        return true;
    else  return false;
}
void GrahamScan(int n)
{
    Point tmp;
    int k = 0;
    for(int i=1; i<n; ++i)//找出y值(y值相同時找x最小)最小的點作爲起始點P0
        if((p[i].y < p[k].y) || ((p[i].y==p[k].y) && (p[i].x<p[k].x)))
            k = i;
    tmp = p[0];
    p[0] = p[k];
    p[k] = tmp;
    sort(p+1,p+n,cmp);// 按極角大小排序
    top = -1;
    st[++top] = p[0];
    st[++top] = p[1];
    st[++top] = p[2];  //先把極角最小的0, 1, 2三點存入棧中
    for(int i=3; i<n; ++i) //從第3點開始,直到最後,如果不能左轉,則退棧.
    {
        while((cross(p[i], st[top],st[top-1]))>=0)    //如果不能左轉,則退棧
            top--;
        st[++top]=p[i];
    }
    ++top;
}
/***********************************************/
int main()
{
    int n,i;
    double s_dist;
    while(scanf("%d",&n)!=EOF)
    {
        if(n==0)
            break;
        else
        {
            for(i=0; i<n; i++)
                scanf("%d%d",&p[i].x,&p[i].y);
            if(n==1)//如果只有一個點
                printf("0\n");
            else if (n==2)//如果有兩個點
                printf("%.2lf\n",dis(p[0],p[1]));
            else
            {
                GrahamScan(n);
                s_dist=dis(st[0],st[top-1]);
                for(i=0; i<top-1; i++)
                    s_dist=s_dist+dis(st[i],st[i+1]);
                printf("%.2lf\n",s_dist);
            }
        }

    }
    return 0;
}



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章