P2742 [USACO5.1]圈奶牛Fencing the Cows /【模板】二維凸包
阿新 • • 發佈:2020-12-20
題目描述
農夫約翰想要建造一個圍欄用來圍住他的奶牛,可是他資金匱乏。他建造的圍欄必須包括他的奶牛喜歡吃草的所有地點。對於給出的這些地點的座標,計算最短的能夠圍住這些點的圍欄的長度。
輸入格式
輸入資料的第一行是一個整數。表示農夫約翰想要圍住的放牧點的數目nn。
第22到第(n + 1)(n+1)行,每行兩個實數,第(i + 1)(i+1)行的實數x_i, y_ixi,yi分別代表第ii個放牧點的橫縱座標。
輸出格式
輸出輸出一行一個四捨五入保留兩位小數的實數,代表圍欄的長度。
輸入輸出樣例
輸入 #14 4 8 4 12 5 9.3 7 8輸出 #1
12.00
說明/提示
資料規模與約定
對於100\%100%的資料,保證1 \leq n \leq 10^51≤n≤105,-10^6 \leq x_i, y_i \leq 10^6−106≤xi,yi≤106。小數點後最多有22位數字。
程式碼:
#include<bits/stdc++.h> using namespace std; const int maxn=1e5+7; struct node { double x,y; }p[maxn],s[maxn];//p用於存原始點,s用於可能存在凸殼上的點並用來模擬棧 double d(node a,node b)//距離 { return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y)); }double check(node a1,node a2,node b1,node b2)//叉積(大於零時為逆時針,等於零平行,小於零順時針) { return (a2.x-a1.x)*(b2.y-b1.y)-(b2.x-b1.x)*(a2.y-a1.y); } int cmp(node a,node b)//按照極角的大小逆時針排序(與x軸正方向) { if(check(p[1],a,p[1],b)>0)return 1; if(check(p[1],a,p[1],b)==0&&d(p[0],a)<d(p[0],b))return 1; return0; } int main() { int n; scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%lf%lf",&p[i].x,&p[i].y); if(i!=1&&p[i].y<p[1].y)swap(p[i],p[1]);//取y最小的點作為凸包的第一個點 } sort(p+2,p+n+1,cmp); s[1]=p[1];//y最小的點一定在凸殼上 int cnt=1; for(int i=2;i<=n;i++) { while(cnt>1&&check(s[cnt-1],s[cnt],s[cnt],p[i])<=0)cnt--;//當前點如果與在它之前加入凸殼的前兩個點形成了一個朝左的凹殼,則說明中間的那個點可以不要 cnt++; s[cnt]=p[i];//入棧 } s[cnt+1]=p[1];//回到最初點 double ans=0; for(int i=1;i<=cnt;i++)ans+=d(s[i],s[i+1]); printf("%.2f",ans); return 0; }