凸包入门(Graham扫描法)(A - Wall POJ - 1113)
题目链接:https://cn.vjudge.net/contest/276359#problem/A
题目大意:有一个国王,要在自己的城堡周围建立围墙,要求围墙能把城堡全部围起来,并且围墙距离城堡的距离至少为l,然后问你最小的消耗量。
具体思路: 将围起来城堡的围墙全部往外移,求出这些点构成的凸包,然后再加上半径为l的圆的周长,这就是最终答案。
AC代码:
1 #include<iostream> 2 #include<stack> 3 #include<iomanip> 4 #include<string> 5 #include<stdio.h> 6 #include<cstring> 7 #include<iomanip> 8 #include<cmath> 9 #include<algorithm> 10 using namespace std; 11 # define ll long long 12 const int maxn = 1e3+100; 13 const double pi= acos(-1.0); 14 struct node 15 { 16 double x,y; 17 } p[maxn],P[maxn]; 18 int n,tot; 19 double ans,l; 20 double X(node A,node B,node C)//求叉积的过程 21 { 22 return (B.x-A.x)*(C.y-A.y)-(C.x-A.x)*(B.y-A.y); 23 } 24 double len(node A,node B) 25 { 26 return sqrt((A.x-B.x)*(A.x-B.x)+(A.y-B.y)*(A.y-B.y)); 27 } 28 bool cmp(node A,node B) 29 { 30 double pp=X(p[0],A,B); 31 if(pp>0) 32 return true; 33 if(pp<0) 34 return false; 35 return len(p[0],A)<len(p[0],B); 36 } 37 int main() 38 { 39 while(~scanf("%d %lf",&n,&l)) 40 { 41 ans=2.0*pi*l; 42 for(int i=0; i<n; i++) 43 { 44 scanf("%lf %lf",&p[i].x,&p[i].y); 45 } 46 if(n==1) 47 { 48 printf("%.0lf\n",ans); 49 } 50 else if(n==2) 51 { 52 printf("%.0lf\n",ans+=len(p[0],p[1])); 53 } 54 else 55 { 56 for(int i=0; i<n; i++) 57 { 58 if(p[i].y<p[0].y) 59 { 60 swap(p[i],p[0]); 61 } 62 else if(p[i].y==p[0].y&&p[i].x<p[0].x) 63 { 64 swap(p[i],p[0]); 65 } 66 }//先把第一个点找出来 67 sort(p+1,p+n,cmp); 68 P[0]=p[0]; 69 P[1]=p[1];//寻找凸包的起点和终点 70 tot=1; 71 for(int i=2; i<n; i++) 72 { 73 while(tot>0&&X(P[tot-1],P[tot],p[i])<=0)//斜率相同的时候,取较远的。 74 tot--; 75 tot++; 76 P[tot]=p[i]; 77 } 78 for(int i=0; i<tot; i++) 79 { 80 ans+=len(P[i],P[i+1]); 81 } 82 ans+=len(P[0],P[tot]); 83 printf("%.0lf\n",ans); 84 } 85 } 86 return 0; 87 } 88