算法:分治法求凸包上的点以及由凸包所构成的多边形的面积

在平面上有若干个点,编写程序求其凸包上的点以及由凸包所构成的多边形的面积。

输入要求:输入的第一行是一个整数n,表示点的个数。其后的n行,每行有两个整数,中间空格隔开,分别表示点的X,Y坐标。

输出要求:输出的第1行为一个整数m,表示凸包上点的个数,其后的m行每行有两个整数,分别表示凸包上点的坐标,最后一行为一个浮点数,精确到小数点后2位。

 此题有很多经典算法,这里用分治的方法求解。

思想:先按横坐标将点集排序,则p0pn必定是凸包点集上的点并且将凸包分为上凸包和下凸包,对于上凸包,求px使其到直线p0pn的距离最长,则其必定是凸包上的点。然后连接p0px,pnpx,其下方的点必定不是凸包的点,因此对其构成的上凸包点集分别按照上述方法求解直到没有上凸包为止。下凸包类似求解。对于面积,将多边形固定一个点分解为多个三角形,随后利用向量的叉积求解三角形面积并求和即可。也可以利用以下行列式

x1 y1 1
x2 y2 1
x3 y3 1
=x1y2+x3y1+x2y3-x3y2-x2y1-x1y3,其1/2即为三角形的面积,此外,这个行列式还可以用来判断点与直线的位置关系,行列式值>0,则点(x3,y3)在p1p2的右侧,<0在左侧。而算法的复杂度的关键步骤是将点集排序为O(nlogn)。

源代码:

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define Del(a,b) memset(a,b,sizeof(a))
using namespace std;
const int N = 1010;
const double esp = 1e-10;
struct Point
{
    double x,y;
    Point(double x=0,double y=0):x(x),y(y) {}
	Point(Point a, Point b):x(b.x-a.x),y(b.y-a.y) {}
};  //坐标点的数据结构定义
typedef Point Vector;
double Cross(Point A, Point B, Point C);//计算向量叉积
double CalArea(Point *p, int n);//计算面积,p为点集
void QuickSort_X(Point *p, int n);//点集按照横坐标排序
void Swap(Point *a, Point *b);//交换点a,b
double Distance(Point p, Vector r, Point q);//求点p到过点q方向向量为r的直线距离
void ConvexHull(Point *, Point *, int);//求解凸包问题
void ConvexHullUp(Point *p, Point *r, int n);//求解上凸包
void ConvexHullDown(Point *p, Point *r, int n);//求解下凸包
int num = 0;//已找到的解的个数
int main()
{
	int n;
	double area;
	while (scanf("%d", &n) == 1)
	{
		Point *p = (Point *)malloc(sizeof(Point)*n);
		Point *r = (Point *)malloc(sizeof(Point)*n);
			for (int i = 0; i < n; i++)
			{
				scanf("%lf%lf", &p[i].x, &p[i].y);
			}
		QuickSort_X(p, n);
		ConvexHull(p, r, n);
		area = CalArea(r, num);
		printf("%d\n", num);
		for (int i = 0; i < num; i++)
		{
			printf("%.2lf %.2lf\n", r[i].x, r[i].y);
		}
		printf("%.2lf\n", area);
	}
	free(p);
	free(r);
	return 0;
}
double CalArea(Point *P, int n)
{
	double Area = 0;
	for (int i = 0; i+1 < n; i++)
    {
		Area += abs(Cross(P[i+1],P[i],P[0]));
    }
	return Area / 2;
}
double Cross(Point A, Point B, Point C)
{
    return A.x*B.y+C.x*A.y+B.x*C.y-A.y*B.x-B.y*C.x-C.y*A.x;
}
void QuickSort_X(Point *p, int n)
{
	int i, j;
	i = 0; j = n - 1;
	int key = 0;
	while (i < j)
	{
		for (; j>=0 && p[j].x >= p[key].x; j--);
		if(j>=key)
		Swap(&p[j], &p[key]);
		for (; i<=n-1 && p[i].x <= p[key].x; i++);
		if (i<=key)
		Swap(&p[i], &p[key]);
	}
	if (n - key - 1 >= 1)
	QuickSort_X(p + key + 1, n - key - 1);
	if (key >= 1)
	QuickSort_X(&p[0], key);
}
void Swap(Point *a, Point *b)
{
	Point *temp=(Point*)malloc(sizeof(Point));
	*temp = *a;
	*a = *b;
	*b = *temp;
}
double Distance(Point p, Vector r, Point q)
{
	double a = -r.y;
	double b = r.x;
	double c = a * q.x + b * q.y;
	c = -c;
	double dis = abs(a*p.x + b*p.y + c);
	dis = dis / sqrt(a*a + b*b);
	return dis;
}
void ConvexHull(Point *p, Point *r, int n) 
{
	int up = 1, down = 1;
	Point *p_up = (Point *)malloc(sizeof(Point)*n);
	Point *p_down = (Point *)malloc(sizeof(Point)*n);
	for (int i = 1; i < n - 1; i++)
	{
		if (Cross(p[0], p[n - 1], p[i]) > 0)
			p_up[up++] = p[i];
		else
			p_down[down++] = p[i];
	}
	r[num++] = p[0];
	r[num++] = p[n-1];
	p_up[0] = p[0];
	p_up[up++] = p[n - 1];
	p_down[0] = p[0];
	p_down[down++] = p[n - 1];
	if (up > 0)
	ConvexHullUp(p_up, r, up);
	if (down > 0)
	ConvexHullDown(p_down, r, down);
	free(p_up);
	free(p_down);
}
void ConvexHullUp(Point *p, Point *r, int n)
{
	double max = 0;
	int t=-1;
	Point *p_up = (Point *)malloc(sizeof(Point)*n);
	int up = 1;
	for (int i = 1; i < n - 1; i++)
	{
		if (Cross(p[0], p[n - 1], p[i]) > 0)
		{
			p_up[up++]=p[i];
			double dis = Distance(p[i], Vector(p[0], p[n - 1]), p[0]);
			if (dis > max)
			{
				max = dis;
				t = i;
			}
		}
	}
	if(t!=-1){
	r[num++] = p[t];
	p_up[0] = p[0];
	p_up[up++] = p[n - 1];
	ConvexHullUp(p_up, r, t+1);
	ConvexHullUp(p_up + t, r, up - t);
	}
	free(p_up);

}
void ConvexHullDown(Point *p, Point *r, int n)
{
	double max = 0;
	int t=-1;
	Point *p_down = (Point *)malloc(sizeof(Point)*n);
	int down = 1;
	for (int i = 1; i < n - 1; i++)
	{
		if (Cross(p[0], p[n - 1], p[i]) < 0)
		{
			p_down[down++] = p[i];
			if (Distance(p[i], Vector(p[0], p[n - 1]), p[0]) > max)
			{
				max = Distance(p[i], Vector(p[0], p[n - 1]), p[0]);
				t = i;
			}
		}
	}
	if (t!=-1){
	r[num++] = p[t];
	p_down[0] = p[0];
	p_down[down++] = p[n - 1];
	ConvexHullDown(p_down, r, t + 1);
	ConvexHullDown(p_down + 1, r, down - t);
	}
	free(p_down);
}


你可能感兴趣的:(acm及算法)