标签:code mes 二维 方向 min scan for iostream span
题意:n个点,求凸包周长。(纯板子QAQ)
定义
凸包:用最小的凸多边形将n个点围在里面的图形为凸包
前置
向量:点积:(a,b) (c,d)=(a*c,b*d) =|(a,b)|*|(c,d)|*cos<(a,b),(c,d)>;
叉积:(a,b) (c,d)=a*d-b*c=|(a,b)|*|(c,d)|*sin<(a,b),(c,d)>;
几何意义:以(a,b)(c,d)两向量作平行四边形,它俩的叉积为其面积
故有三角形面积=$\large{\frac{1}{2}*|(a,b)|*|(c,d)|*sin<(a,b),(c,d)>}$
极角:与x轴的夹角,STL库有atan2函数,atan2(y,x)求出向量(x,y)的极角
算法
1、找到最左下的点,以其为原点建立平面直角坐标系
2、求出各点新坐标以及极角
3、以极角为关键字从小到大排序
4、前三个点入栈
5、用叉积判方向看当前栈顶应不应该留下,留下则当前点入栈,否则一直弹(直到能够留下)
6、第5步后,栈中元素即为所需点,相邻两个作差求模长,累计即为答案
#include<algorithm> #include<cstdio> #include<iostream> #include<cmath> using namespace std; #define olinr return #define love_nmr 0 struct node { double x,y,jj; node():x(0),y(0),jj(0){} friend node operator - (const node &a,const node &b) { node c; c.x=a.x-b.x; c.y=a.y-b.y; olinr c; } friend double operator ^ (const node &a,const node &b) { olinr a.x*b.y-a.y*b.x; } double mo() { olinr sqrt(x*x+y*y); } friend bool operator < (const node &a,const node &b) { olinr a.jj<b.jj; } }cow[10505]; int n; double ans; int s[20505]; int top; int minn=1; inline void swap(node &x,node &y) { node t=x; x=y; y=t; } int main() { scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%lf%lf",&cow[i].x,&cow[i].y); if((cow[i].y<cow[minn].y)||((cow[i].y==cow[minn].y)&&(cow[i].x<cow[minn].x))) minn=i; } swap(cow[1],cow[minn]); for(int i=2;i<=n;i++) { cow[i].x-=cow[1].x; cow[i].y-=cow[1].y; cow[i].jj=atan2(cow[i].y,cow[i].x); } cow[1].x=0; cow[1].y=0; sort(cow+2,cow+1+n); s[1]=1; s[2]=2; s[3]=3; top=3; for(int i=4;i<=n;i++) { while(top>2&&((cow[s[top]]-cow[s[top-1]])^(cow[i]-cow[s[top]]))<0) top--; s[++top]=i; } for(int i=1;i<top;i++) ans+=(cow[s[i+1]]-cow[s[i]]).mo(); ans+=(cow[n]-cow[1]).mo(); printf("%.2lf",ans); olinr love_nmr; }
P2742 【模板】二维凸包 / [USACO5.1]圈奶牛Fencing the Cows
标签:code mes 二维 方向 min scan for iostream span
原文地址:https://www.cnblogs.com/olinr/p/9474825.html