NYOJ78——圈水池

题目链接:http://acm.nyist.net/JudgeOnline/problem.php?pid=78
题目分析:
这道题其实就是给若干的点,然后求这些点的凸包,最后将这些点的凸包按x坐标从小到大的顺序输出,如果x坐标相同,就按y坐标从小到大输出。
至于求凸包的步骤,要是没有图的话,很难描述。如果有叉乘的概念的话,看代码应该就可以理解一点。有时间的时候再把图贴上细讲吧。下面给出大概的步骤。
1、首先要在给出的点列中,找到最左下角的点,作为基准点。
2、将其他剩余的点,以找到的左下角的点为基准点,进行逆时针排序,最后将基准点加进去,因为基准点既是始点,也是终点。
3、对排序后的点求凸包。
4、对求得的凸包,按要求输出。
对照着代码和实现步骤,将就看吧~
参考代码:

#include<stdio.h>
#include<stdlib.h>

const int N = 105;
typedef struct  
{
	int x;
	int y;
}POINT;

POINT point[N];
POINT stack[N];
inline int CrossProduct(const POINT *a, const POINT *b, const POINT *c)
{//计算向量(b-a)×(b-c)
	return (a->x - b->x) * (b->y - c->y) - (b->x - c->x) * (a->y - b->y);
}

//将每个点按照向量(point[0] - point[i])顺时针排列
int compare1(const void *a, const void *b)
{
	POINT *p1 = (POINT *)a;
	POINT *p2 = (POINT *)b;
	return CrossProduct(&point[0], p1, p2);
}

int compare2(const void *a, const void *b)
{
	POINT *p1 = (POINT *)a;
	POINT *p2 = (POINT *)b;
	if(p1->x == p2->x)
		return p1->y - p2->y;
	else
		return p1->x - p2->x;
}

int Convex(int n)
{
	int top = 2;
	stack[0] = point[0];
	stack[1] = point[1];
	stack[2] = point[2];
	for(int i = 3; i < n; ++i)
	{
		while(CrossProduct(&stack[top - 1], &stack[top], &point[i]) >= 0)
			--top;
		stack[++top] = point[i];
	}
	return top;
}

int main()
{
	int t,n;
	int i,Index;
	POINT temp;
	scanf("%d", &t);
	while(t--)
	{
		scanf("%d",&n);
		for(i = 0; i < n; ++i)
			scanf("%d %d",&point[i].x, &point[i].y);

		//找到左下角的点,放在point[0]里面。
		Index = 0;
		for(i = 1; i < n; ++i)
		{
			if(point[i].x <= point[Index].x && point[i].y <= point[Index].y)
				Index = i;
		}
		temp = point[0];
		point[0] = point[Index];
		point[Index] = temp;
		//将所有点按顺时针排序
		qsort(&point[1], n - 1, sizeof(point[0]),compare1);
		//最后加入point[0];
		point[n] = point[0];
		++n;

		Index = Convex(n);
		qsort(stack, Index, sizeof(stack[0]), compare2);//最后对得到的凸包中的点进行排序
		for(i = 0; i < Index; ++i)
			printf("%d %d\n",stack[i].x, stack[i].y);
	}
	return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值