模板 凸包 旋转卡壳

模板  凸包  旋转卡壳

 

 

lrj 《训练指南》 P272

对于个点按照 x 从小到大排序,再按照 y 点从小到大排序,删除重复的点后,得到序列 p0,p1,p2...,
把 p0 和 p1 放入凸包。 从p2开始,当新点在凸包“前进”方向的左边时继续,否则依次删除最近加入凸包的点,直到新点在左边
PS:判断用叉积即可
模板 凸包 旋转卡壳
 
 
 1 /********************************************

 2 计算凸包,输入点数组 p, 个数为 n , 输出点数组 ch. 函数返回凸包顶点数

 3 输入不能有重复点。函数执行完之后输入点的顺序被破坏

 4 如果不希望在凸包的边上有输入点,把两个 <= 改成 < 【== 表示两向量共线】

 5 在精度要求高时建议用 dcmp 比较

 6 

 7 const double eps = 1e-10;

 8 int dcmp(double x)

 9 {

10     if(fabs(x) < eps) return 0;

11     else return x < 0 ? -1 : 1;

12 }

13 ********************************************/

14 double ConvexHull(Point* p, int n, Point* ch) /** 基于水平的Andrew算法求凸包 */

15 {

16     sort(p,p+n,cmp); /**先按照 x 从小到大排序, 再按照 y 从小到大排序*/

17     int m = 0;

18 

19     for(int i = 0; i < n; i++) /** 从前往后找,求"下凸包" */

20     {/**Cross <= 0有等于,去掉 重复的点*/

21         while(m > 1 && Cross(ch[m-1]-ch[m-2], p[i]-ch[m-2]) <= 0) m--;

22         ch[m++] = p[i];

23     }

24     int k = m;

25     for(int i = n-2; i >= 0; i--) /**从后往前找,求"上凸包" 形成完整的封闭背包*/

26     {

27         while(m > k && Cross(ch[m-1]-ch[m-2], p[i]-ch[m-2]) <= 0) m--;

28         ch[m++] = p[i];

29     }

30     if(n > 1) m--; /** 起点重复 */

31     return m;

32 }

33 

34 旋转卡壳模板:

35 

36 盗版的别人博客的模板,下面会贴上大牛的关于这个算法的分析,一般是能看懂的了,如果不能看懂的,记住就好了

37 

38 

39 int rotating_calipers(Point *ch, int m) /**旋转卡壳模板*/

40 {

41     int q = 1;

42     int ans = 0;

43     ch[m] = ch[0]; /**凸包边界处理*/

44     for(int i = 0; i < m; i++) /**依次用叉积找出凸包每一条边对应的最高点*/

45     {/**同底不同高,每次用面积判断高的大小就可以了*/

46         while(Cross(ch[i+1]-ch[i], ch[q+1]-ch[i]) > Cross(ch[i+1]-ch[i], ch[q]-ch[i]))

47             q = (q+1)%m;

48     /**每条底上有两个点,所以要 max 两次*/

49         ans = max(ans, max(squarDist(ch[i], ch[q]), squarDist(ch[i+1], ch[q+1])));

50     }

51     return ans;/**返回的也就是凸包的直径*/

52 }

 

 

思路:

暴力:最远距离两个点一定在凸包上,建立好背包后,枚举凸包上的点就可以了
对于凸包上的点很多,暴力的话肯定是不行的了,那么就用旋转卡壳,只是名字听着神奇,其实也很好理解了
旋转卡壳:直接套模板,求直径
 

code1:暴力+凸包【对应于凸包上点比较少】

 

 1 /********************************************

 2 题意:给你 N 个点, 求所有点中最远两点距离

 3 算法:凸包+暴力

 4 思路:最远距离两个点一定在凸包上,建立好背包后,枚举凸包上的点就可以了

 5 *********************************************/

 6 #include<stdio.h>

 7 #include<math.h>

 8 #include<string.h>

 9 #include<algorithm>

10 using namespace std;

11 

12 const int maxn = 50000+10;

13 int n,m;

14 

15 struct Point{

16     double x,y;

17     Point(){};

18     Point(double _x, double _y)

19     {

20         x = _x;

21         y = _y;

22     }

23 

24     Point operator - (const Point & B) const

25     {

26         return Point(x-B.x, y-B.y);

27     }

28 }p[maxn], ch[maxn];

29 

30 bool cmp(Point p1, Point p2)

31 {

32     if(p1.x == p2.x) return p1.y < p2.y;

33     return p1.x < p2.x;

34 }

35 

36 int squarDist(Point A, Point B) /**距离的平方*/

37 {

38     return (A.x-B.x)*(A.x-B.x) + (A.y-B.y)*(A.y-B.y);

39 }

40 

41 double Cross(Point A, Point B) /**叉积*/

42 {

43     return A.x*B.y-A.y*B.x;

44 }

45 

46 void ConvexHull() /** 求凸包 */

47 {

48     sort(p,p+n,cmp); /**先按照 x 从小到大排序, 再按照 y 从小到大排序*/

49     m = 0;

50 

51     for(int i = 0; i < n; i++) /** 从前往后找"下凸包" */

52     {

53         while(m > 1 && Cross(ch[m-1]-ch[m-2], p[i]-ch[m-2]) <= 0) m--;

54         ch[m++] = p[i];

55     }

56     int k = m;

57     for(int i = n-2; i >= 0; i--) /**从后往前找"上凸包", 形成完整的封闭背包*/

58     {

59         while(m > k && Cross(ch[m-1]-ch[m-2], p[i]-ch[m-2]) <= 0) m--;

60         ch[m++] = p[i];

61     }

62     if(n > 1) m--; /** 起点重复*/

63 }

64 

65 int main()

66 {

67     while(scanf("%d", &n) != EOF)

68     {

69         if(n == 0) break;

70         for(int i = 0; i < n; i++)

71             scanf("%lf%lf", &p[i].x, &p[i].y);

72 

73         ConvexHull();

74         int ans = 0;

75         for(int i = 0; i < m; i++)

76             for(int j = i+1; j < m; j++)

77                 ans = max(ans,squarDist(ch[i], ch[j]));

78         printf("%d\n", ans);

79     }

80     return 0;

81 }
View Code

 

 

code2:凸包+旋转卡壳【对于凸包上点比较多】

 

 

 1 /********************************************

 2 2187    Accepted    972K    297MS   C++ 1927B   2013-07-27 13:38:35

 3 题意:给你 N 个点, 求所有点中最远两点距离

 4 算法:凸包+旋转卡壳

 5 思路:最远距离两个点一定在凸包上,建立好背包后,直接套用旋转卡壳找直径

 6 *********************************************/

 7 #include<stdio.h>

 8 #include<math.h>

 9 #include<string.h>

10 #include<algorithm>

11 using namespace std;

12 

13 const int maxn = 50000+10;

14 int n,m;

15 

16 struct Point{

17     double x,y;

18     Point(){};

19     Point(double _x, double _y)

20     {

21         x = _x;

22         y = _y;

23     }

24 

25     Point operator - (const Point & B) const

26     {

27         return Point(x-B.x, y-B.y);

28     }

29 }p[maxn], ch[maxn];

30 

31 bool cmp(Point p1, Point p2)

32 {

33     if(p1.x == p2.x) return p1.y < p2.y;

34     return p1.x < p2.x;

35 }

36 

37 int squarDist(Point A, Point B) /**距离的平方*/

38 {

39     return (A.x-B.x)*(A.x-B.x) + (A.y-B.y)*(A.y-B.y);

40 }

41 

42 double Cross(Point A, Point B) /**叉积*/

43 {

44     return A.x*B.y-A.y*B.x;

45 }

46 

47 void ConvexHull() /** 基于水平的Andrew算法求凸包 */

48 {

49     sort(p,p+n,cmp); /**先按照 x 从小到大排序, 再按照 y 从小到大排序*/

50     m = 0;

51 

52     for(int i = 0; i < n; i++) /** 从前往后找 */

53     {

54         while(m > 1 && Cross(ch[m-1]-ch[m-2], p[i]-ch[m-2]) <= 0) m--;

55         ch[m++] = p[i];

56     }

57     int k = m;

58     for(int i = n-2; i >= 0; i--) /**从后往前找, 形成完整的封闭背包*/

59     {

60         while(m > k && Cross(ch[m-1]-ch[m-2], p[i]-ch[m-2]) <= 0) m--;

61         ch[m++] = p[i];

62     }

63     if(n > 1) m--;

64 }

65 

66 int rotating_calipers() /**旋转卡壳模板*/

67 {

68     int q = 1;

69     int ans = 0;

70     ch[m] = ch[0]; /**凸包边界处理*/

71     for(int i = 0; i < m; i++) /**依次用叉积找出凸包每一条边对应的最高点*/

72     {

73         while(Cross(ch[i+1]-ch[i], ch[q+1]-ch[i]) > Cross(ch[i+1]-ch[i], ch[q]-ch[i]))

74             q = (q+1)%m;

75         ans = max(ans, max(squarDist(ch[i], ch[q]), squarDist(ch[i+1], ch[q+1])));

76     }

77     return ans;

78 }

79 

80 int main()

81 {

82     while(scanf("%d", &n) != EOF)

83     {

84         if(n == 0) break;

85         for(int i = 0; i < n; i++)

86             scanf("%lf%lf", &p[i].x, &p[i].y);

87 

88         ConvexHull();

89 

90         printf("%d\n", rotating_calipers());

91     }

92     return 0;

93 }
View Code

 

 

 

 另外还有关于凸包周长的题目

 

 

 

你可能感兴趣的:(模板)