【洛谷P2742】【模板】二维凸包/[USACO5.1]圈奶牛【凸包】
题目大意:
题目链接: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;
}