hdu1392-Surround the Trees-(凸包)

 

凸包概念:坐标上有好多好多点,把外围的点连起来,所有点都包括在线上或者里面,此时周长最小。看起来每个角凸出去,简称凸包。

 

顺序:1.找基点 2.自定义按其他点和基点之间的斜率排序 3.按顺序找出符合条件的点压进凸包集合

 

https://vjudge.net/problem/HDU-1392

题意:有好多树,从最外围围起来,篱笆要多长?

思路:凸包模板题,记录代码

#include<stdio.h>
#include<math.h>
#include<algorithm>///sort需要的函数
using namespace std;

struct node
{
    int x;
    int y;
};
node p[105];
node tu[105];
int n,top;
///叉积是矢量概念,如果结果大于0,p0p1在p0p2的顺时针方向
double chaji(node p0,node p1,node p2)
{   ///叉积公式=x1*y2-x2*y1,叉积是矢量概念,如果结果大于0,p0p1在p0p2的顺时针方向
    return (p1.x-p0.x)*(p2.y-p0.y)-(p2.x-p0.x)*(p1.y-p0.y);
}   ///叉积的绝对值是三个点围成面积的一半

double dis(node p1,node p2)
{
    return sqrt( (p1.x-p2.x)*(p1.x-p2.x)+(p1.y-p2.y)*(p1.y-p2.y) );
}

bool cmp(node p1,node p2)///比较函数,只能两两相比
{
    double z=chaji(p[0],p1,p2);
    if( z>0 || (z==0&&dis(p[0],p1)<dis(p[0],p2)) )
        return true;///返回真,则p1排在p2前
    return false;
}

void Graham()///从基点开始寻找外围的点
{//葛立恒发明的算法
    double z;
    tu[0]=p[0];
    tu[1]=p[1];///这两个点总会放进凸包里
    top=1;
    for(int i=2;i<n;i++)
    {
        while( chaji(tu[top-1],tu[top],p[i])<0 )///通过p[i]判断tu[top]是不是符合要求
            top--;///top-1,继续判断,直到找到符合条件的top,下面会覆盖掉原来的不符合条件的下标内容
        top++;
        tu[top]=p[i];
    }
    ///最后一个点在基点和倒数第二点的连线之外,必然是凸出去的
}
int main()
{
    while(scanf("%d",&n) && n)
    {
        for(int i=0;i<n;i++)///输入杂乱无章的各点坐标
            scanf("%d%d",&p[i].x,&p[i].y);
        if(n==1)
            {printf("0\n");continue;}
        else if(n==2)
            {printf("%.2lf\n",dis(p[0],p[1]));continue;}
        int k=0;
        for(int i=0;i<n;i++)
            if( p[k].y>p[i].y || (p[k].y==p[i].y&&p[k].x>p[i].x) )
                k=i; ///找基点下标,越下越左的
        swap(p[0],p[k]);///目前还没有排序,只要确定基点,其他随便换
        sort(p+1,p+n,cmp);///按自定义的排序方法排序
        Graham();
        double len=0;///算凸包外面的长度
        for(int i=0;i<top;i++)
            len += dis(tu[i],tu[i+1]);
        len += dis(tu[0],tu[top]);
        printf("%.2f\n",len);
    }
}

 

posted @ 2018-08-12 20:52  守林鸟  阅读(148)  评论(0编辑  收藏  举报