POJ 1113 凸包周长
题意:
国王想建一个周长最短的城墙,使墙的任意一点到城墙的距离都 大于 rr。求这面墙的周长。
题解:
凸包 水平序graham扫描法
显然答案就是:凸包的周长+半径为rr的圆的周长
View Code
1 #include <iostream> 2 #include <cstdlib> 3 #include <cstdio> 4 #include <algorithm> 5 #include <cstring> 6 #include <cmath> 7 8 #define N 1010 9 #define EPS 1e-7 10 #define PI 3.1415926535 11 12 using namespace std; 13 14 struct PO 15 { 16 double x,y; 17 }p[N],stk[N]; 18 19 double rr,ans; 20 int n; 21 22 inline bool cmp(const PO &a,const PO &b) 23 { 24 if(a.x==b.x) return a.y<b.y; 25 return a.x<b.x; 26 } 27 28 inline void read() 29 { 30 scanf("%d%lf",&n,&rr); 31 for(int i=1;i<=n;i++) scanf("%lf%lf",&p[i].x,&p[i].y); 32 } 33 34 inline double cross(const PO &o,const PO &a,const PO &b) 35 { 36 return (a.x-o.x)*(b.y-o.y)-(b.x-o.x)*(a.y-o.y); 37 } 38 39 inline double get_dis(const PO &a,const PO &b) 40 { 41 return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y)); 42 } 43 44 inline void graham() 45 { 46 sort(p+1,p+1+n,cmp); 47 int top=0; 48 for(int i=1;i<=n;i++) 49 { 50 while(top>=2&&cross(stk[top-1],stk[top],p[i])<-EPS) top--;//cross()==0时不能弹栈! 51 stk[++top]=p[i]; 52 } 53 for(int i=n-1;i>=1;i--) 54 { 55 while(top>=2&&cross(stk[top-1],stk[top],p[i])<-EPS) top--; 56 stk[++top]=p[i]; 57 } 58 ans=0.0; 59 for(int i=1;i<top;i++) ans+=get_dis(stk[i],stk[i+1]); 60 } 61 62 inline void go() 63 { 64 graham(); 65 ans+=2.0*rr*PI; 66 printf("%.0lf\n",ans+EPS); 67 } 68 69 int main() 70 { 71 read(),go(); 72 return 0; 73 }
特别说明:
一般的我们求的凸包是使其中的点尽量少,也就是说,若多点共线,只保留两个端点,判断的时候就是叉积等于0时也弹栈,但是这样会有bug
当叉乘的两个向量相反时,就会弹栈,出现错误!
样例真良心,样例就能拍出这个错!
又写了一个优化的:
View Code
1 #include <iostream> 2 #include <cstdlib> 3 #include <cstdio> 4 #include <algorithm> 5 #include <cstring> 6 #include <cmath> 7 8 #define N 1010 9 #define EPS 1e-7 10 #define PI 3.1415926535 11 12 using namespace std; 13 14 struct PO 15 { 16 double x,y; 17 }p[N]; 18 19 double rr,ans; 20 int n,stk[N]; 21 22 inline bool cmp(const PO &a,const PO &b) 23 { 24 if(a.x==b.x) return a.y<b.y; 25 return a.x<b.x; 26 } 27 28 inline void read() 29 { 30 scanf("%d%lf",&n,&rr); 31 for(int i=1;i<=n;i++) scanf("%lf%lf",&p[i].x,&p[i].y); 32 } 33 34 inline double cross(const PO &o,const PO &a,const PO &b) 35 { 36 return (a.x-o.x)*(b.y-o.y)-(b.x-o.x)*(a.y-o.y); 37 } 38 39 inline double get_dis(const PO &a,const PO &b) 40 { 41 return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y)); 42 } 43 44 inline void graham() 45 { 46 sort(p+1,p+1+n,cmp); 47 int top=0; 48 stk[++top]=1; stk[++top]=2; 49 for(int i=3;i<=n;i++) 50 { 51 while(top>=2&&cross(p[stk[top-1]],p[stk[top]],p[i])<EPS) top--; 52 stk[++top]=i; 53 } 54 int num=top; 55 for(int i=n-1;i>=1;i--) 56 { 57 while(top>num&&cross(p[stk[top-1]],p[stk[top]],p[i])<EPS) top--; 58 stk[++top]=i; 59 } 60 ans=0.0; 61 for(int i=1;i<top;i++) ans+=get_dis(p[stk[i]],p[stk[i+1]]); 62 } 63 64 inline void go() 65 { 66 graham(); 67 ans+=2.0*rr*PI; 68 printf("%.0lf\n",ans+EPS); 69 } 70 71 int main() 72 { 73 read(),go(); 74 return 0; 75 }
没有人能阻止我前进的步伐,除了我自己!