計算幾何 graham 最大凸包
阿新 • • 發佈:2019-01-01
凸包的嚴格凸多邊形 |
Time Limit: 1000ms, Special Time Limit:2500ms, Memory Limit:32768KB |
Total submit users: 39, Accepted users: 35 |
Problem 11326 : No special judgement |
Problem description |
凸包(convex hull),對於給定集合X,所有包含X的凸集的交集稱為X的凸包,記作con(X)。 對於ACMer來說,這麼嚴格複雜的定義可能是沒有必要的。我們只要知道平面有限點集的凸包是一個凸多邊形就行了。 現在的問題是給定一個平面點集,求出其“嚴格凸多邊形”的凸包。“嚴格”的意思是凸多邊形的邊上沒有任意三點共線。 |
Input |
輸入有多個案例。每個案例的第一行是一個整數n,n≤100。隨後n行,每一行有2個整數,表示點的x、y座標,0≤x、y≤2147483647。一個單獨的0表示輸入結束。沒有任何點的座標是完全一樣的。 |
Output |
對每一個案例,首先輸出一行為其端點的個數,然後按逆時針輸出其凸包的頂點的座標。輸出起點是所有頂點的最下最左點(首先是最下,如果有多個點同樣處於最下,則取最靠左的)。每個頂點輸出一行,中間用空格隔開。 |
Sample Input |
3 0 0 100 100 100 0 0 |
Sample Output |
3 0 0 100 0 100 100 |
//嚴格凸包 #include <cstdio> #include <cmath> #include <algorithm> using namespace std; typedef long long llt; #define SIZE 101 struct point_t{ llt x,y; }P[101]; //叉積,OA×OB llt cross(point_t const&O,point_t const&A,point_t const&B){ llt xoa = A.x - O.x; llt yoa = A.y - O.y; llt xob = B.x - O.x; llt yob = B.y - O.y; return xoa * yob - xob * yoa; } //A如果比B更靠下更靠左返回真 bool isLowLeft(point_t const&A,point_t const&B){ return A.y < B.y || ( A.y == B.y && A.x < B.x ); } //按照對於pO的極角排序,極角相等的距離遠的排在前面,因為後面要做一個unique point_t* pO; bool comp4Graham(point_t const&A,point_t const&B){ llt t = cross(*pO,A,B); if ( t ) return t > 0LL; llt a1 = A.x > pO->x ? A.x - pO->x : pO->x - A.x; llt a2 = B.x > pO->x ? B.x - pO->x : pO->x - B.x; if ( a1 != a2 ) return a1 > a2; a1 = A.y > pO->y ? A.y - pO->y : pO->y - A.y; a2 = B.y > pO->y ? B.y - pO->y : pO->y - B.y; return a1 > a2; } //相對於pO是否極角相等 bool isEqPolar(point_t const&A,point_t const&B){ return 0LL == cross(*pO,A,B); } //Graham求凸包,結果當中沒有共線點,起點總是最下最左點 int Graham(point_t P[],int n){ if ( 1 == n ) return 1; //尋找最下最左點 point_t *p = min_element(P,P+n,isLowLeft); //交換 swap(*p,P[0]); if ( 2 == n ) return 2; //按極角排序,極角相等,距離近的排在前面 pO = P; sort(P+1,P+n,comp4Graham); //將相對於pO的共線點均剔除,只保留最後一個 p = unique(P+1,P+n,isEqPolar); n = p - P; //真正的Graham迴圈 int top = 2; for(int i=2;i<n;++i){ while( top > 1 && cross(P[top-2],P[top-1],P[i]) <= 0LL ) --top; P[top++] = P[i]; } return top; } int main(){ int n; while( scanf("%d",&n) && n ){ for(int i=0;i<n;++i)scanf("%I64d%I64d",&P[i].x,&P[i].y); n = Graham(P,n); printf("%d\n",n); for(int i=0;i<n;++i)printf("%I64d %I64d\n",P[i].x,P[i].y); } return 0;
凸包的不嚴格凸多邊形 |
Time Limit: 1000ms, Special Time Limit:2500ms, Memory Limit:32768KB |
Total submit users: 19, Accepted users: 15 |
Problem 11327 : No special judgement |
Problem description |
凸包(convex hull),對於給定集合X,所有包含X的凸集的交集稱為X的凸包,記作con(X)。 對於ACMer來說,這麼嚴格複雜的定義可能是沒有必要的。我們只要知道平面有限點集的凸包是一個凸多邊形就行了。 現在的問題是給定一個平面點集,求出其“不嚴格”凸多邊形的凸包。“不嚴格”的意思是指將凸包邊界上所有的點都看作是多邊形的端點。 |
Input |
輸入有多個案例。每個案例的第一行是一個整數n,n≤100。隨後n行,每一行有2個整數,表示點的x、y座標,0≤x、y≤2147483647。一個單獨的0表示輸入結束。 |
Output |
對每一個案例,首先輸出一行為多邊形端點的個數,然後按逆時針輸出其凸包的頂點的座標。輸出起點是所有頂點的最下最左點(首先是最下,如果有多個點同樣處於最下,則取最靠左的)。每個頂點輸出一行,中間用空格隔開。 |
Sample Input |
4 0 0 100 100 100 0 50 0 0 |
Sample Output |
4 0 0 50 0 100 0 100 100 |
嚴格凸包是在極角排序的時候提前做了處理,所以我們只要把處理取反即可, 程式碼上只要把極角相等的時候改成近的放前面,去掉unique函式。
typedef long long llt;
struct point_t{
llt x,y;
}P[101];
llt cross(point_t const&O,point_t const&A,point_t const&B){
llt xoa = A.x - O.x;
llt yoa = A.y - O.y;
llt xob = B.x - O.x;
llt yob = B.y - O.y;
return xoa * yob - xob * yoa;
}
bool isLowLeft(point_t const&A,point_t const&B){
return A.y < B.y || ( A.y == B.y && A.x < B.x );
}
point_t* pO;
bool comp4Graham(point_t const&A,point_t const&B){
llt t = cross(*pO,A,B);
if ( t ) return t > 0LL;
llt a1 = A.x > pO->x ? A.x - pO->x : pO->x - A.x;
llt a2 = B.x > pO->x ? B.x - pO->x : pO->x - B.x;
if ( a1 != a2 ) return a1 < a2; //把這個變成近的放前面
a1 = A.y > pO->y ? A.y - pO->y : pO->y - A.y;
a2 = B.y > pO->y ? B.y - pO->y : pO->y - B.y;
return a1 > a2;
}
bool isEqPolar(point_t const&A,point_t const&B){
return 0LL == cross(*pO,A,B);
}
int Graham(int n){
if ( 1 == n ) return 1;
point_t *p = min_element(P,P+n,isLowLeft);
swap(*p,P[0]);
if ( 2 == n ) return 2;
pO = P;
sort(P+1,P+n,comp4Graham);
//去掉這個
//p = unique(P+1,P+n,isEqPolar);
//n = p - P;
int top = 2;
for(int i=2;i<n;++i){
while( top > 1 && cross(P[top-2],P[top-1],P[i]) < 0LL )
--top;
P[top++] = P[i];
}
return top;
}
int main(){
int n;
while( scanf("%d",&n) && n ){
for(int i=0;i<n;++i)scanf("%I64d%I64d",&P[i].x,&P[i].y);
n = Graham(n);
printf("%d\n",n);
for(int i=0;i<n;++i)printf("%I64d %I64d\n",P[i].x,P[i].y);
}
return 0;
}