二維凸包
阿新 • • 發佈:2021-11-11
#include<bits/stdc++.h> using namespace std; #define N 1000010 const int mod = 1000000007; const int inf = 1000000007; const double eps = 1e-9; void in(int &x){ x=0;char c=getchar(); int y=1; while(c<'0'||c>'9'){if(c=='-')y=-1;c=getchar();} while(c>='0'&&c<='9'){x=(x<<3)+(x<<1)+c-'0';c=getchar();} x*=y; } void o(int x){ if(x<0){x=-x;putchar('-');} if(x>9)o(x/10); putchar(x%10+'0'); } int sgn(double x){ if (x>eps)return 1; if (x<-eps)return -1; return 0; } // 向量 struct vec{ double x,y; vec(){x=y=0;} vec(double _x,double _y){x=_x,y=_y;} // 向量四則運算 vec operator + (vec v){return vec(x+v.x,y+v.y);} vec operator - (vec v){return vec(x-v.x,y-v.y);} vec operator * (double v){return vec(x*v,y*v);} vec operator / (double v){return vec(x/v,y/v);} double operator * (vec v){return x*v.x+y*v.y;} }; // 按照 x 為第一關鍵字, y 為 第二關鍵字排序 bool cmpXY(vec a,vec b){ if (sgn(a.x-b.x))return a.x<b.x; return a.y<b.y; } // 叉乘 // 叉乘 大於 相同 表示 對於一個點來說 時針 順逆相同 double cross(vec a ,vec b){ return a.x*b.y-a.y*b.x; } // 計算凸包 int convec_hull(vec*v,int n,vec* z){ // 先安裝關鍵字排個序 sort(v,v+n,cmpXY); // z 為手動模擬的一個棧 int m = 0; // for(int i=0;i<n;i++){ // 位於逆時針方向 且 棧非空 出棧 while (m>1 && cross(z[m-1]-z[m-2],v[i]-z[m-2])<=0)--m; // 入棧 z[m++] = v[i]; } int k = m; // 從 n - 2 開始 因為 n-1 即隊尾必在凸包中 for(int i=n - 2;i>=0;--i) { // 同理,判棧 while( m > k && cross(z[m-1]-z[m-2],v[i]-z[m-2]) <= 0 ) --m; // 入棧 z[m++] = v[i]; } // 初始點重複入棧,退出 if(n>1)--m; return m; } double Length(vec x){ return sqrt(x.x*x.x+x.y*x.y); } int n; vec a[N],ans[N]; signed main(){ in(n); for(int i=0;i<n;i++){ cin>>a[i].x>>a[i].y; } int m=convec_hull(a,n,ans); double ANS=0.0; // 輸出長度 for(int i=0;i<m;i++){ ANS += Length(ans[i+1]-ans[i]); } printf("%.2lf\n",ANS); return 0; }