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 }

 

 

你可能感兴趣的:(poj)