向量叉积问题(凸包)

学凸包时不太理解叉积判断,学完后就整理了一下,希望对大家有点帮助


  • 向量叉积:

向量A×B(叉积)的代数定义:(A.x-B.y)* (A.y-B.x)

若A×B的值为正,A在B的顺时针方向;反之亦然(值为0共线)

“顺时针方向”(此处31在21的顺时针方向):

RTAaQg.png

  • cross函数:

此函数计算:线段ab×线段cb(将b看作原点)

double cross(point a,point b,point c){return (a.x-b.x)*(c.y-b.y)-(a.y-b.y)*(c.x-b.x);}
  • 单调栈维护弹出点:

以上图为例,线段21在线段31的逆时针方向,弹出21,

RTZ4mQ.png

for(int i=1;i<=n;++i){
	while(num>1&&cross(s[num],s[num-1],a[i])<=0) --num;//s[num]在a[i]的逆时针方向 
	s[++num]=a[i];
}
  • andrew构建凸包模板:

dalao的andrew构建凸包详解

#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
using namespace std;
const int maxn=10003;
int n,num;
struct point{double x,y;}a[maxn],s[maxn];
double dis(point a,point b){return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));}
bool cmp(point a,point b){return a.x==b.x?a.y<b.y:a.x<b.x;}
double cross(point a,point b,point c){return (a.x-b.x)*(c.y-b.y)-(a.y-b.y)*(c.x-b.x);}//a叉c 
void andrew(){
	sort(a+1,a+n+1,cmp);
	for(int i=1;i<=n;++i){
		while(num>1&&cross(s[num],s[num-1],a[i])<=0) --num;//a在c的逆时针方向 
		s[++num]=a[i];
	}
	for(int i=n-1,tmp=num;i;--i){
		while(num>tmp&&cross(s[num],s[num-1],a[i])<=0) --num;
		s[++num]=a[i];
	}
	if(n>1) --num;
}
int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;++i) scanf("%lf %lf",&a[i].x,&a[i].y);
	andrew();
	double ans=dis(s[num],s[1]);
	for(int i=1;i<num;++i) ans+=dis(s[i],s[i+1]);
	printf("%.2lf",ans);
	return 0;
}
原文地址:https://www.cnblogs.com/wuwendongxi/p/14978045.html