凸包問題—Graham掃描法
阿新 • • 發佈:2019-02-20
#include<iostream> #include<cmath> #include<algorithm> using namespace std; struct point { long long x; long long y; } P[50005], S[50005]; //P中存點,S模擬棧存凸包的點; long long xx; long long yy; // 計算各個點相對於P0的幅角α,按從小到大的順序對各個點排序 bool cmp(struct point a, struct point b) { if(atan2(a.y-yy,a.x-xx) != atan2(b.y-yy,b.x-xx)) //atan2函式求幅角 return (atan2(a.y-yy,a.x-xx)) < (atan2(b.y-yy,b.x-xx)); // 當α相同時(在同一條直線上),距離P0比較近的排在前面 if (a.x != b.x) return abs(a.x) < abs(b.x); return abs(a.y) < abs (b.y); } //叉積判斷c在直線ab的位置 long long Compare(struct point a, struct point b, struct point c) { return ((a.x-c.x)*(b.y-c.y)-(b.x-c.x)*(a.y-c.y)); // (x1-x)*(y2-y)-(x2-x)*(y1-y) } int main() { int n,i,j; while(cin>>n) { yy=1000005; for(i=0; i<n; i++) { cin>>P[i].x>>P[i].y; if(P[i].y < yy) { yy=P[i].y; // 記錄縱座標最小的點(xx,yy) 及位置 i xx=P[i].x; j=i; } } P[j]=P[0]; // P[j]是凸包上的點,刪去後按照幅角排序 sort(P+1, P+n, cmp); S[0].x=xx; S[0].y=yy; S[1]=P[1]; //P[1]也是凸包上的點,入棧 int top=1; for(i=2; i<n;) { if(top && (Compare(S[top-1], S[top], P[i]) < 0)) //表示棧頂元素不為凸包上的點,棧頂元素出棧,繼續判斷當前點 top--; else //表示當前點為凸包上的點,入棧 S[++top]=P[i++]; } if (P[n-1].x==xx) //排除一種情況 { top--; for (i=n-1; i>=2; i--) if (P[i].x==xx) S[++top]=P[i]; } for(i=0; i<=top; i++) cout<<"("<<S[i].x<<","<<S[i].y<<")"<<endl; } return 0; } /* 測試資料 9 0 0 2 3 4 1 1 2 3 3 3 6 4 4 -1 4 -2 3 (0,0) (4,1) (4,4) (3,6) (-1,4) (-2,3) 4 0 0 0 2 0 1 1 1 (0,0) (1,1) (0,2) (0,1) */