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 }

 

 

posted @ 2013-02-14 20:28  proverbs  阅读(265)  评论(0编辑  收藏  举报