凸包、半平面交

凸包

凸包是什么?

想象在平面上有若干个钉子,将无限大的橡皮筋突然松开,勒紧后形成的图形称为凸包。

模板问题:平面上给定一堆点,求凸包

有两种算法可以求凸包,Graham算法和Andraw算法,这里说的是Andraw算法
第一步:将点排序,横坐标为第一关键字,纵坐标为第二关键字

第二步:从左到右维护上半部分,从右到左维护下半部分

第三步:再次维护起点

double area(pdd a,pdd b,pdd c)//面积
{
	return cross(b-a,c-a);//叉积
}

double andraw()
{
	sort(q,q+n);
	int top=0;//栈顶元素 
	for(int i=0;i<n;i++)//从左到右枚举所有点
	{
		while(top>=2&&area(q[stk[top-1]],q[stk[top]],q[i])>=0)//左侧删除,通过area函数面积的正负判断在哪侧
		{
		    // 凸包边界上的点即使被从栈中删掉,也不能删掉used上的标记
		    if(area(q[stk[top-1]],q[stk[top]],q[i])>0)
			used[stk[top--]]=false;
			else top--;
	    } 
	    stk[++top]=i;
	    used[i]=true;
	} 
	used[0]=false;//第一个点再更新一遍
	for(int i=n-1;i>=0;i--)
	{
		if(used[i])
		continue;
		while(top>=2&&area(q[stk[top-1]],q[stk[top]],q[i])>=0)
		top--;
		stk[++top]=i;
	} 
	double res=0;
	for(int i=2;i<=top;i++)//起点两次
	{
		res+=get_dist(q[stk[i-1]],q[stk[i]]);
	} 
	return res;
}

半平面交

半平面交解决这样一类问题:

给定很多有向直线,只保留直线左侧部分,求保留的交集

第一步:将所有向量按角度排序

求角度用actan2函数,此函数 y 在前,x 在后

第二步: 按顺序扫描所有向量,用双端队列维护轮廓

(直线用点向式存储)

double half_plane_intersection()
{
	sort(line,line+cnt,cmp);//按照角度排序
	int hh=0,tt=-1;
	for(int i=0;i<cnt;i++)
	{
		//去掉重复角度 
		if(i&&!dcmp(get_angle(line[i]),get_angle(line[i-1]))) continue;
		while(hh+1<=tt&&on_right(line[i],line[q[tt-1]],line[q[tt]]))//类似于求凸包
		tt--;
		while(hh+1<=tt&&on_right(line[i],line[q[hh]],line[q[hh+1]]))
		hh++;
		q[++tt]=i;
	}
	//队头更新队尾,队尾更新队头 
	while(hh+1<=tt&&on_right(line[q[hh]],line[q[tt-1]],line[q[tt]]))
	tt--;
	while(hh+1<=tt&&on_right(line[q[tt]],line[q[hh]],line[q[hh+1]]))
	hh++;
	
	q[++tt]=q[hh];
	int k=0;
	for(int i=hh;i<tt;i++)
	ans[k++]=get_line_intersection(line[q[i]],line[q[i+1]]);//求两个函数交点的函数
	double res=0;
	for(int i=1;i+1<k;i++)
	res+=area(ans[0],ans[i],ans[i+1]);//面积函数
	return res/2;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值