【洛谷P2742】【模板】二维凸包/[USACO5.1]圈奶牛【凸包】

题目大意:

题目链接:https://www.luogu.org/problemnew/show/P2742
求二维平面上的凸包。


思路:

二维凸包模板题。在这里就不讲述凸包的概念和做法了。需要的话可以看本题题解
采用的是GrahamGraham算法,时间复杂度O(n logn)O(n\ logn)


代码:

#include <cstdio>
#include <stack>
#include <cmath>
#include <algorithm>
using namespace std;

const int N=100010;
int n,t=1;
double ans;

struct node  //记录平面上的点的坐标
{
    double x,y;
}a[N];
stack<node> s;   //栈

double cal(double x1,double y1,double x2,double y2)  //求距离
{
    return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
}

double angle(node x,node y,node z)
//求x,y在以z为原点平面直角坐标系中的叉积
{
    return (x.x-z.x)*(y.y-z.y)-(y.x-z.x)*(x.y-z.y);
}

bool cmp(node x,node y)  //按照极角排序
{
    double m=angle(x,y,a[1]); 
    if (m>0.0||(m==0.0&&cal(a[1].x,a[1].y,x.x,x.y)<cal(a[1].x,a[1].y,y.x,y.y)))
        return 1;
    return 0;
}

int main()
{
    scanf("%d",&n);
    for (int i=1;i<=n;i++)
    {
        scanf("%lf%lf",&a[i].x,&a[i].y);
        if (a[i].x<a[t].x||(a[i].x==a[t].x&&a[i].y<a[t].y)) t=i;              
        //记录y坐标最小的点(有多个就x尽量小)
    }
    swap(a[1],a[t]);
    sort(a+2,a+1+n,cmp);
    s.push(a[1]);
    s.push(a[2]);
    s.push(a[3]);  //前三个点入栈
    for (int i=4;i<=n;i++)
    {
        while (1)
        {
            node top=s.top();  //栈顶元素
            s.pop();
            if (angle(top,a[i],s.top())>0)  //求叉积,判断哪个点更优
            {
                s.push(top);  //出栈不会更优就入栈
                break;
            }
        }
        s.push(a[i]);
    }
    s.push(a[1]);
    while (s.size()>1)  //依次弹出栈中的点
    {
        node top=s.top();
        s.pop();
        ans+=cal(top.x,top.y,s.top().x,s.top().y);  //求这一条边的距离
    }
    printf("%.2lf\n",ans);
    return 0;
}
posted @ 2019-01-05 14:12  全OI最菜  阅读(115)  评论(0编辑  收藏  举报