学凸包时不太理解叉积判断,学完后就整理了一下,希望对大家有点帮助
- 向量叉积:
向量A×B(叉积)的代数定义:(A.x-B.y)* (A.y-B.x)
若A×B的值为正,A在B的顺时针方向;反之亦然(值为0共线)
“顺时针方向”(此处31在21的顺时针方向):
- 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,
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构建凸包模板:
#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;
}