http://acm.hunnu.edu.cn/online/?action=problem&type=show&id=11326&courseid=117
凸包的严格凸多边形 |
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;
http://acm.hunnu.edu.cn/online/?action=problem&type=show&id=11327&courseid=117
凸包的不严格凸多边形 |
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;
}