模板 凸包 旋轉卡殼

模板  凸包  旋轉卡殼html

 

 

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

 

 

 

 另外還有關於凸包周長的題目數組

相關文章
相關標籤/搜索