模板 凸包 旋轉卡殼html
lrj 《訓練指南》 P272算法
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 }
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 }
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 }