计算几何:凸包

极点:在一组点中,若沿着某一个点做直线,必然能找到一条直线使得所有点都在直线的另一侧,则这个点为极点。

凸包:给定二维平面上的点集,凸包就是将最外层的点连接起来构成的凸多边形,它能包含点集中所有的点

 

平面的一个子集S被称为是“凸”的,当且仅当对于任意两点p,s∈S,线段ps都完全属于S。(平面凸包定义):

计算凸包:

Graham扫描法: 复杂度O(nlogn) 

求得凸包中的点是按逆时针排序的

<=表示如果存在共线的极点,则只取端点

扫描方法有两种,可以用极角序(按极角排序)或坐标序(按x坐标排序,x坐标一样按y坐标排序,其中扫描上凸包是从大到小,扫描下凸包是从小到大)

  1. 找到最左下的点(即y最小,y一样取最左边的),赋给p[1]
  2. 以p[1]作为极点,将所有点按极角排序,极角相同则按距离排序(去掉极角相同的,只留下距离最远的那个点)
  3. 求凸包时while循环把发现不是凸包顶点的点移除出去。因为当逆时针遍历凸包时,我们应该在每个顶点向左转,因此当while循环发现在一个顶点处没有向左转时,就把该顶点移除出去。

计算凸包周长:

hdu1392:Surround the Trees

//以左下点为极点求凸包周长

#include<bits/stdc++.h>
using namespace std;

struct point{
    double x,y;
    point friend operator -(point a,point b)
    {return {a.x-b.x,a.y-b.y};}
}p[105],s[105];//p为所有点的集合,s为凸包点集
double dis(point a,point b)
{
    point c=a-b;
    return sqrt(c.x*c.x+c.y*c.y);
}
double cross(point a,point b)
{
    return a.x*b.y-a.y*b.x;
}
//按照极角(polar angle)从小到大排序(以 p1为极点)
//极角相同的点按照到的距离从小到大排序。
int cmp(point a,point b)
{
    double x=cross(a-p[1],b-p[1]);

    if(x>0) return 1;
    if(x==0&&dis(a,p[1])<dis(b,p[1])) return 1;
    return 0;
}
double multi(point p1,point p2,point p3)//计算向量叉积
{
    return cross(p2-p1,p3-p1);
}
int main()
{
    int N;
    while(scanf("%d",&N),N)
    {
        for(int i=1;i<=N;i++) cin>>p[i].x>>p[i].y;

        if(N==1)
        {
            printf("0.00\n");
            continue;
        }
        else if(N==2)
        {
            printf("%.2lf\n",dis(p[1],p[2]));
            continue;
        }

        int k=1;
        for(int i=2;i<=N;i++)
        if(p[i].y<p[k].y||(p[i].y==p[k].y&&p[i].x<p[k].x))k=i;
        swap(p[1],p[k]);//找到处于最左下方的点,赋给p[1]

        sort(p+2,p+1+N,cmp);//对点按极角排序,p[1]为极点

        s[1]=p[1];
        s[2]=p[2];
        int cnt=2;
        //while循环把发现不是凸包顶点的点移除出去,因为当逆时针遍历凸包时,我们应该在每个顶点向左转
        //因此当while循环发现在一个顶点处没有向左转时,就把该顶点移除出去。
        for(int i=3;i<=N;i++)//求凸包
        {
            while(cnt>=2&&multi(s[cnt-1],s[cnt],p[i])<=0) cnt--;
            s[++cnt]=p[i];
        }
        double sum=0;
        for(int i=1;i<cnt;i++)//求凸包周长
            sum+=dis(s[i],s[i+1]);
        printf("%.2f\n",sum+dis(s[1],s[cnt]));
        /*
        double area=0;
        for(int i=2;i<=cnt-1;i++)//求凸包面积,这里因为就是凸多边形所以可以用某个顶点作为顶点分割三角形
            area+=fabs(multi(s[1],s[i],s[i+1]));
        printf("%d\n",int(area/100));
        */
        /*标准求多边形面积,别漏了最后一个和起点的叉积
        for(int i=1;i<=cnt;i++)//求凸包面积
            area+=cross(s[i],s[i==cnt?1:i+1]);
        if(area<0)
            area=-area;
        */
    }
    return 0;
}

分治法:求解上凸包和下图包合并

  1. 按横坐标从小到大(再总坐标从小到大)排序,首先排序后的起终点必然在凸包里
  2. 连接p1pn,这条直线将点集分成了上下两个部分,则在这两个部分中分别求得上、下凸包
  3. 对于上凸包,找到上部分离直线最远的点pmax,连接p1max,pmaxpn,则直线p1pmax右将上部分分成了两个凸包部分
  4. 重复,求下凸包类似
  5. 判断点位于直线的左侧还是右侧可以用叉积

è¿éåå¾çæè¿°

//这是三个点的叉乘(判断第三个点p3在直线p1p2的左方还是右方)左方>0
double multi(node p1, node p2, node p3)
{
	return p1.x*p2.y+p3.x*p1.y+p2.x*p3.y-p3.x*p2.y-p2.x*p1.y-p1.x*p3.y;
}

上凸包:即将点按x坐标从小到大排序,相当于以y轴负无穷处某一点为极点,从右往左扫描极点。这样算出来的凸包为上凸包。即在左右端点上方的极点

下凸包:即将点按x坐标从小到大排序,相当于以y轴负无穷处某一点为极点,从左往右扫描极点。这样算出来的凸包为上凸包。即在左右端点上方的极点

poj1113:Wall

theme:求能围住所有的点且距离所有点的距离>=L的围墙的长度

solution:即凸包周长+2*pi*L

//求能围住所有的点且距离所有点的距离>=L的围墙的长度

#include<iostream>
#include<cmath>
#include<cstdio>
#include<algorithm>
using namespace std;

struct Point
{
	double x, y;

	Point operator-(Point & p)
	{
		Point t;
		t.x = x - p.x;
		t.y = y - p.y;
		return t;
	}

	double cross(Point p)
	{
		return x*p.y - p.x*y;
	}

	double dist(Point & p)
	{
		return sqrt((x - p.x)*(x - p.x) + (y - p.y)*(y - p.y));
	}
};

bool cmp(Point p1, Point p2)//先横坐标从小到大,再纵坐标从小到大
{
	if (p1.x != p2.x)
		return p1.x < p2.x;
	return p1.y < p2.y;
}

Point point[1005];
int convex[1005];
int N, L;

//返回极点个数+1
int getConvexHull()
{
	sort(point, point + N, cmp);
	int temp;
	int total = 0;
	for (int i = 0; i < N; i++)//求解下凸包,<=关系则如果存在共线的点只取端点
	{
		while (total > 1 && (point[convex[total - 1]] - point[convex[total - 2]]).cross(point[i] - point[convex[total - 1]]) <= 0)
			total--;
		convex[total++] = i;
	}
	//求解上凸包
	temp = total;
	for (int i = N - 2; i >= 0; i--)
	{
		while (total > temp && (point[convex[total - 1]] - point[convex[total - 2]]).cross(point[i] - point[convex[total - 1]]) <= 0)
			total--;
		convex[total++] = i;
	}
	return total;//返回组成凸包的点的个数,实际上多了一个,是起点(开始与最后都是起点),所以组成凸包的点个数是total-1
}

int main()
{
	scanf("%d%d", &N, &L);
	for (int i = 0; i < N; i++)
		scanf("%lf%lf", &point[i].x, &point[i].y);

	int num = getConvexHull();
	double ans = 0.0;
	for (int i = 0; i < num - 1; i++)
		ans += point[convex[i]].dist(point[convex[i + 1]]);
	ans += 3.14159265358927 * 2 * L;
	printf("%.0f\n", ans);
	return 0;
}
/*
9 100
200 400
300 400
300 300
400 300
400 400
500 400
500 200
350 200
200 200

1628
*/

稳定凸包

即由这些点构成的凸多边形唯一,无论再添加多少新的点都不可能再形成别的凸多边形。

结论:稳定凸多边形的任意一条边的点数>=3

        

左边的凸包是不稳定的,因为加上一个点后可以形成一个新的凸多边形。

可以看出如果一个凸多边形的某一条边上只有端点两个点的话,则这个凸多边形是不稳定的。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
《周培德 计算几何:算法设计与分析.pdf》是一本介绍计算几何算法的书籍。计算几何是计算机科学中的一个重要分支,研究的是如何通过计算机来处理和解决几何学相关的问题。 这本书的作者是周培德,他是计算几何领域的专家,曾经在华盛顿大学任教,并发表了大量的计算几何相关的研究论文。他的研究成果在学术界有很高的影响力。 《周培德 计算几何:算法设计与分析.pdf》主要介绍了计算几何的基本概念和常用的算法设计与分析方法。这本书的内容非常全面,涵盖了平面几何,立体几何以及高维几何等多个方面的知识。 这本书首先介绍了计算几何的基本概念,包括点,线,面等几何元素的表示和计算方式。然后,详细讲解了计算几何中常用的算法,如:点的位置关系判断算法,凸包算法,最近点对算法等。 此外,这本书还介绍了计算几何中常用的数据结构,如:平衡树,网格树等,以及它们与算法设计和分析的关系。同时,还介绍了计算几何在图形学,计算机模拟,机器人等领域的应用。 总的来说,《周培德 计算几何:算法设计与分析.pdf》是一本非常重要的计算几何教材,对于想要深入了解和研究计算几何的学生和专业人士来说是很有价值的参考资料。无论是学术研究还是实际应用,这本书都可以提供很多有用的知识和方法。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值