凸包--HDU - 3285 Convex Hull of Lattice Points

Description

A lattice point is a point with integer coordinates. A lattice polygon is a polygon with all vertices lattice points. 

A polygon is convex if any line segment between two points of the polygon is inside (or on the boundary of) the polygon. Equivalently, the interior angle at each polygon vertex is less than 180 degrees. 

For a set S, of lattice points, the convex hull is the smallest convex (lattice) polygon which contains all points of the set. (The vertices of the convex hull must be members of the set of lattice points). If all the points are on a single straight line, the convex hull will be a line segment (a degenerate polygon � see rightmost diagram below). In the diagrams below, the points of the set are indicated by solid dots, the vertices of the convex hull by X’s and the convex hull is drawn connecting the vertices. 
Note that not all points on the convex hull polygon are vertices. 

The vertices of a lattice polygon are in standard order if: 
a) The first vertex is the one with the largest y value. If two vertices have the same y value, the one with the smaller x value is the first. 
b) Vertices are given in clockwise order around the polygon. 

Write a program that reads a set of lattice points and outputs the vertices of the convex hull of the points in standard order.
 

Input

The first line of input contains a single integer P, (1 ≤ P ≤ 1000), which is the number of data sets that follow. The first line of each data set contains the data set number, followed by a space, followed by a decimal integer giving the number of points N, (3 ≤ N ≤ 50), in the set. The remaining lines in the data set contain the points in the set, at most 5 points per line (the last line may have fewer). Each point consists of 2 space separated decimal integer values representing the x and y coordinates 
respectively.
 

Output

For each data set there are multiple lines of output. The first line contains a decimal integer giving the data set number followed by a single space, followed by a decimal integer giving the total number of vertices of the convex hull. The vertices of the convex hull follow, one per line in standard order. Each line contains the decimal integer x coordinate, a single space and the decimal integer y coordinate.
 

Sample Input

    
    
4 1 25 2 1 7 1 1 2 9 2 1 3 10 3 1 4 10 4 1 5 10 5 2 6 10 6 2 7 9 7 3 8 8 8 4 9 7 9 6 2 3 3 5 4 7 5 8 6 4 6 3 7 2 30 3 9 6 9 3 8 9 8 3 7 12 7 2 6 12 6 2 5 12 5 2 4 12 4 1 3 11 3 1 2 11 2 1 1 11 1 1 0 10 0 4 -1 10 -1 7 -2 10 -2 5 0 7 3 4 5 6 8 3 1 2 6 3 3 3 1 2 2 1 3 4 6 1 3 19 1 4 2 2 1 11 2 10 1
 

Sample Output

    
    
1 10 4 9 7 9 10 6 10 3 9 2 7 1 2 1 1 2 1 5 2 7 2 8 3 9 6 9 12 7 12 4 10 -2 7 -2 1 0 1 3 3 2 1 3 3 1 4 4 1 3 11 2 19 1 2 1


分析:典型的凸包问题,凸包的思路大致如下:

1、接收输入数据,同时找到左下角的点(y最小,若y等则x最小)

2、对数据按照极坐标角坐标从小到大排序

3、将前两个点入栈

4、循环处理接下来的n-2个点,如果当前点和栈中的前两个点不满足to_left,则栈顶减1,如果满足到第5步

5、栈顶加1,将当前点入栈,回到第4步

这样处理完后的栈实际上就是最小凸包,其中的 to_left 是左转检测,即判断第三个点是否在前两个点向量的左侧;

注意题目要求从y最大(若y等则x最小)的点开始顺时针输出点集,而一般的凸包是逆时针处理,所以最后输出前需要找到栈中y最大(y等则x最小)的点,然后分别逆序输出其左部分点和右部分点即可。


#include <cstdio>
#include <algorithm>
using namespace std;
const int maxn = 55;
struct Point { int x, y; };
Point p[maxn], stk[maxn];

int to_left(const Point& a, const Point& b, const Point& c)
{
	return (b.y-a.y)*(c.x-a.x) - (b.x-a.x)*(c.y-a.y);
}

int dis(const Point& a, const Point& b)
{
	return (a.x-b.x)*(a.x-b.x) + (a.y-b.y)*(a.y-b.y);
}

bool cmp(const Point& a, const Point& b)
{
    int t = to_left(p[0], a, b);
    return t<0 || (t==0 && dis(p[0], a)<dis(p[0], b));
}

int main()
{
    int T;
    scanf("%d", &T);
    while(T--) {
		int kase, n;
		scanf("%d%d", &kase, &n);
		int k = 0;
		for(int i=0; i<n; i++) {
			scanf("%d%d", &p[i].x, &p[i].y);
			if(p[i].y<p[k].y || (p[i].y==p[k].y && p[i].x<p[k].x)) k = i;
		}
		swap(p[0], p[k]);
		sort(p+1, p+n, cmp);

		stk[0] = p[0]; stk[1] = p[1];
		int top = 1;
        for(int i=2; i<n; i++) {
			while(top && to_left(stk[top-1], stk[top], p[i])>=0) top--;
			stk[++top] = p[i];
        }
        k = 0;
        for(int i=1; i<=top; i++) {
			if(stk[i].y>stk[k].y || (stk[i].y==stk[k].y && stk[i].x<stk[k].x)) k = i;
        }
        printf("%d %d\n", kase, top+1);
        for(int i=k; i>=0; i--)
            printf("%d %d\n", stk[i].x, stk[i].y);
		for(int i=top; i>k; i--)
			printf("%d %d\n", stk[i].x, stk[i].y);
    }
    return 0;
}


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值