1. 程式人生 > >【洛谷P2742】【模板】二維凸包/[USACO5.1]圈奶牛【凸包】

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

題目大意:

題目連結:https://www.luogu.org/problemnew/show/P2742
求二維平面上的凸包。


思路:

二維凸包模板題。在這裡就不講述凸包的概念和做法了。需要的話可以看本題題解
採用的是 G r a h a m

Graham 演算法,時間複雜度 O ( n   l o g n
) 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; }