二維凸包求解(Andrew演算法 )
阿新 • • 發佈:2018-12-21
Andrew演算法是Graham演算法的變種。
其主要思想為把凸包上的點依次放入棧中,
如果發現形成了凹多邊形(叉積為負值)
就刪除一些點,使得又能夠維持凸的形態。
這時就會發現,處理各個點需要按照x從左往右的順序,排序即可
當然,這只是處理了下凸的一個凸殼,倒過來再刷一次,就得到了整個凸包
程式碼:
#include <iostream> #include <cmath> #include <cstdio> #include <algorithm> #include <fstream> #include <string> #include <sstream> using namespace std; struct point { int x,y; }pt[1005]; int sta[1005], ans[1005], cnt; int cmp(point a, point b) { //左下角優先,先左後下 return a.x < b.x || (a.x == b.x && a.y < b.y); } int cross(point p0, point p1, point p2) { //大於0,逆時針方向 return (p1.x-p0.x)*(p2.y-p0.y)-(p1.y-p0.y)*(p2.x-p0.x); } //Andrew演算法 void convex(int n) { sort(pt, pt+n, cmp); cnt = 0; int top = 0; sta[top++] = 0; //先處理 下凸包 sta[top++] = 1; for(int i = 2; i < n; ++i) { while(top > 1 && cross(pt[sta[top-2]], pt[sta[top-1]], pt[i]) <= 0) { top--; } sta[top++] = i; } for(int i = 0; i < top; ++i) { ans[cnt++] = sta[i]; } top = 0; //求上凸包,並將pt[n-1]與pt[0]連線起來 sta[top++] = n - 1; sta[top++] = n - 2; for(int i = n - 3; i >= 0; --i) { while(top > 1 && cross(pt[sta[top-2]], pt[sta[top-1]], pt[i]) <= 0) { top--; } sta[top++] = i; } for(int i = 0; i < top; ++i) { ans[cnt++] = sta[i]; //兩個凸包的頭結點和尾結點存入兩次 } } int main() { ifstream in("points.txt"); if(in) { string line; string data1; string data2; stringstream input; int num = 0; int sz; bool first = true; while(getline(in, line)) { if(first) { sz = stoi(line); // cout << "sz = " << sz << endl; first = false; } else { input.clear(); input.str(line); input >> data1 >> data2; // cout << "data1 = " << data1 << endl; pt[num].x = stoi(data1); pt[num].y = stoi(data2); ++num; } } //cout << "num = " << num << endl; // num == 9 //計算9個點組成的凸包 convex(9); //輸出凸包點的座標 for(int i = 0; i < cnt; ++i) { cout << "x = " << pt[ans[i]].x << " y = " << pt[ans[i]].y << endl; } } else { cout << "no such file" << endl; } return 0; } /************points.txt******************* 9 1 3 2 7 3 1 4 5 5 4 6 9 7 8 8 2 9 6 ******************************************/