[nyoj78]圈水池(凸包入门)

圈水池

时间限制: 3000 ms  |  内存限制: 65535 KB
难度: 4
描述
有一个牧场,牧场上有很多个供水装置,现在牧场的主人想要用篱笆把这些供水装置圈起来,以防止不是自己的牲畜来喝水,各个水池都标有各自的坐标,现在要你写一个程序利用最短的篱笆将这些供水装置圈起来!(篱笆足够多,并且长度可变)
输入
第一行输入的是N,代表用N组测试数据(1<=N<=10)
第二行输入的是m,代表本组测试数据共有m个供水装置(3<=m<=100)
接下来m行代表的是各个供水装置的横纵坐标
输出
输出各个篱笆经过各个供水装置的坐标点,并且按照x轴坐标值从小到大输出,如果x轴坐标值相同,再安照y轴坐标值从小到大输出
样例输入
1
4
0 0
1 1
2 3
3 0
样例输出
0 0
2 3
3 0
题解:
这题是赤裸裸的凸包入门题。凸包指的就是利用给定点,把其余给定点包围起来所形成的、面积最小的、凸多边形。

[nyoj78]圈水池(凸包入门) - qqxufo - ~~~~~~~网络连接中断~~~~~~~    凸包
   [nyoj78]圈水池(凸包入门) - qqxufo - ~~~~~~~网络连接中断~~~~~~~
 
     不是凸包
由于本人也只是初学,所以这里简单的介绍一下Andrew算法,Andrew是基于水平序的一种算法(且不能有重复点)。
我们要做的第一步是将给定点按照x从小到大排序,若x相同则按照y从小到大排序。设排序好之后的点序列为p1,p2,p3,.... ,pn我们需要先将最左边的两个点A,B加入 到凸包集合中,接着对下一个点C进行判断,判断向量AC是否在向量AB的下方,如果是,那么将B点从凸包集合中删除,加入新的点,如图1,C符合条件,所以我们将B点删除。
接着再对下一个点进行判断,将它与凸包集合里的后两个点进行比较,还是判断新形成的向量是否在下方,是的话则删除凸包集合的最后一个点,接着继续将新的点加入到集合(不管凸包集合的最后一个点是否被删除,都加入新的点),如图2,新的点不符合条件,所以我们凸包集合中的最后一个点不用删除,直接将新点加入到凸包集合中。
那么我们循环n次之后就可以得到凸包的下半部分  (图5)。于是我们再反着求一次,就可以得到凸包的上部分了,凸包就完成了。。

[nyoj78]圈水池(凸包入门) - qqxufo - ~~~~~~~网络连接中断~~~~~~~
小tips:
这里计算两个向量Vector1和Vector2的位置关系我们可以利用两个向量的叉积,如果叉积大于0,则说明Vector1在Vector2的上方
完整代码:
#include<stdio.h>
#include<math.h>
#include<stdlib.h>
#include<algorithm>
using namespace std;
struct Point{
	double x,y;
	Point(double x=0,double y=0):x(x),y(y){		

	}

}p[110],ch[110];

typedef Point Vector;//定义Point的别名

//对自定义的结构体进行运算符重载
Vector operator - (Vector A,Vector B){

	return Vector(A.x-B.x,A.y-B.y); 

}
Vector operator * (Vector A,double p){

	return Vector(A.x*p,A.y*p); 

}
bool operator < (const Point &A,const Point &B){

	return A.x<B.x||(A.x==B.x&&A.y<B.y);//先比较x,如果x相同接着比较y

}
//计算叉积

double Cross(Vector A,Vector B){

	return A.x*B.y-A.y*B.x;

}
void Andrew(Vector *p,int n,Vector *ch){

	sort(p,p+n);//对点从小到大排序

	//凸包下部分

	int m=0;

	for(int i=0;i<n;i++)

	{

		while(m>1&&Cross(ch[m-1]-ch[m-2],p[i]-ch[m-2])<=0) m--;//这里的m>1是确保凸包集合中至少存在一个向量

		ch[m++]=p[i];

	}

	//凸包上部分	

	int k=m;

	for(int i=n-2;i>0;i--)

	{
	    while(m>k&&Cross(ch[m-1]-ch[m-2],p[i]-ch[m-2])<=0) m--;
	    
		ch[m++]=p[i];
	}

	sort(ch,ch+m);
	for(int i=0;i<m;i++)
	{
		printf("%.0f %.0f\n",ch[i].x,ch[i].y);
	}

}

int main()

{
	int t;
	int n;
	scanf("%d",&t);
	while(t--)
	{

		scanf("%d",&n);
		for(int i=0;i<n;i++)
		{

			int a,b;

			scanf("%d%d",&a,&b);

			p[i].x=a;

			p[i].y=b;
		}
		Andrew(p,n,ch);
	}
	return 0;
}


 
 

转载链接:https://blog.csdn.net/code_tank/article/details/26113385

猜你喜欢

转载自blog.csdn.net/qq_40816078/article/details/81027960