题目链接:P2742 [USACO5.1]圈奶牛Fencing the Cows /【模板】二维凸包 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)https://www.luogu.com.cn/problem/P2742
Andrew算法:
-
按照x优先的顺序排序(坐标从小到大)
-
从第一个点开始遍历,如果下一个点在栈顶的两个元素所连成直线的左边,那么就入栈;
-
否则如果在右边,说明凸包有更优的方案,上次的点出栈,并直到新点在栈顶两个点所在的直线的左边为止
#include<bits/stdc++.h> #define lmw ios::sync_with_stdio(0);cin.tie(0);cout.tie(0) #define int long long using namespace std; #define x first #define y second typedef pair<double,double> pdd; const int N=1000010; int n; pdd q[N]; int s[N]; bool used[N]; double get_dist(pdd a,pdd b){ double dx=a.x-b.x; double dy=a.y-b.y; return sqrt(dx*dx+dy*dy); } pdd operator-(pdd a,pdd b){ return {a.x-b.x,a.y-b.y}; } double cross(pdd a,pdd b){ return a.x*b.y-a.y*b.x; } double area(pdd a ,pdd b,pdd c){ pdd A=pdd(b.x-a.x,b.y-a.y); pdd B=pdd(c.x-a.x,c.y-a.y); return cross(A,B); } double andrew(){ sort(q,q+n); int top=0; for(int i=0;i<n;i++){ while(top>=2&&area(q[s[top-1]],q[s[top]],q[i])>=0){ used[s[top--]]=0; } s[++top]=i; used[i]=1; } used[0]=0; for(int i=n-1;i>=0;i--){ if(used[i]) continue; while(top>=2&&area(q[s[top-1]],q[s[top]],q[i])>=0) top--; s[++top]=i; } double res=0.0; for(int i=2;i<=top;i++){ res+=get_dist(q[s[i-1]],q[s[i]]); } return res; } signed main(){ lmw; cin>>n; for(int i=0;i<n;i++){ cin>>q[i].x>>q[i].y; } double res=andrew(); cout<<fixed<<setprecision(2)<<res<<"\n"; }