题目大意
n个点构成的城堡,给出每个点的坐标。若要修建距离城堡最近距离为L的城墙,问城墙的最短长度。
凸包模板题,用Andrew算法求出凸包然后加上半径为L的圆的周长即可。
Andrew算法
首先对所有点按照y大小进行升序排序,如果y相同就按照x大小升序排序。
构造上凸包
前两个点直接入栈。随后遍历其他点,利用叉积判断每个点能否于它的前两个点构成凸多边形。
如果是就入栈。
如果不是就回溯,不断地删除最后一个入栈的点,直到栈中只剩下一个点或者栈顶的两个点能与当前的点构成凸多边形。
构造下凸包
与构造上凸包同理。回溯时要注意不能删除上凸包的点。
代码
1 #include <bits/stdc++.h> 2 #define IO ios::sync_with_stdio(0), cin.tie(0), cout.tie(0); 3 using namespace std; 4 5 const int N = 1001; 6 int n, tot; 7 struct node 8 { 9 double x, y; 10 } a[N], p[N]; 11 12 double dis(node A,node B) 13 { 14 return sqrt((B.x - A.x) * (B.x - A.x) + (B.y - A.y) * (B.y - A.y)); 15 } 16 17 double cross(node A,node B,node C) 18 { 19 return (B.x - A.x) * (C.y - A.y) - (C.x - A.x) * (B.y - A.y); 20 } 21 bool cmp(node A,node B) 22 { 23 if(A.y!=B.y) 24 return A.y < B.y; 25 return A.x < B.x; 26 } 27 void Andrew(double l) 28 { 29 sort(a + 1, a + n + 1, cmp); 30 tot = 0; 31 for (int i = 1; i <= n; i++) 32 { 33 while(tot>1&&cross(p[tot-1],p[tot],a[i])<=0) 34 tot--; 35 p[++tot] = a[i]; 36 } 37 double ans = 0; 38 int temp = tot; 39 for (int i = n - 1; i >= 1; i--) 40 { 41 while(tot>temp&&cross(p[tot-1],p[tot],a[i])<=0) 42 tot--; 43 p[++tot] = a[i]; 44 } 45 for (int i = 1; i < tot;i++) 46 { 47 ans += dis(p[i], p[i + 1]); 48 } 49 cout << int(ans + 2.0 * acos(-1) * l + 0.5) << endl; 50 } 51 signed main() 52 { 53 IO; 54 double l; 55 cin >> n >> l; 56 for (int i = 1; i <= n;i++) 57 cin >> a[i].x >> a[i].y; 58 Andrew(l); 59 return 0; 60 }
标签:node,return,wall,double,tot,凸包,int,tzoj1471 From: https://www.cnblogs.com/yosuganosora/p/17624448.html