【洛谷P2742】【模板】二維凸包/[USACO5.1]圈奶牛【凸包】
阿新 • • 發佈:2019-01-05
題目大意:
題目連結:https://www.luogu.org/problemnew/show/P2742
求二維平面上的凸包。
思路:
二維凸包模板題。在這裡就不講述凸包的概念和做法了。需要的話可以看本題題解。
採用的是
演算法,時間複雜度
。
程式碼:
#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;
}