洛谷P2742 Fencing the Cows

传送门

题解

二维凸包模板题。
使用简单迅速的 Graham Scan 算法可以直接求出整个凸包。算法流程:

  • 选出所有点中 y 坐标最小的点,作为原点,建立极坐标系。
  • 将其余点以极角排序,极角相同看长度
  • 将基准点与第一点入栈,依次扫描之后的点,设栈顶点为 \(b\),栈顶之下一个点为 \(a\),当前扫描到的点是 \(c\),如果 \(\vec{ab}\) 转向 \(\vec{ac}\) 为顺时针,那么将 \(b\) pop出栈。判断位置使用向量叉积实现,如果顺时针,那么 \(\vec{ab}\times\vec{ac}<0\)
  • 扫描完所有点之后,栈里面的所有点构成凸包。

代码

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <algorithm>
#define xx first
#define yy second
using namespace std;
typedef long long LL;
typedef pair<double,double> PDD;
const int N=3e5+10;
const double PI=acos(-1.0);
int n,top;
PDD p[N],sta[N];
double ans;
double X(PDD a,PDD b,PDD c){
	return (b.xx-a.xx)*(c.yy-a.yy)-(c.xx-a.xx)*(b.yy-a.yy);
}
double len(PDD a,PDD b){
	return sqrt((a.xx-b.xx)*(a.xx-b.xx)+(a.yy-b.yy)*(a.yy-b.yy)); 
}
bool cmp(PDD a,PDD b){
	double pp=X(p[1],a,b);
	if(pp>0) return true;
	if(pp<0) return false;
	return len(p[1],a)<len(p[1],b);
}

int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++) scanf("%lf%lf",&p[i].xx,&p[i].yy);
	if(n==1) return printf("0.00\n"),0;
	else if(n==2) return printf("%.2lf\n",len(p[1],p[2])),0;
	for(int i=1;i<=n;i++)
		if(p[i].yy<p[1].yy||p[i].yy==p[1].yy&&p[i].xx<p[1].xx)
			swap(p[i],p[1]);
	sort(p+2,p+n+1,cmp);
	sta[++top]=p[1];sta[++top]=p[2];
	for(int i=3;i<=n;i++){
		while(top>1&&X(sta[top-1],sta[top],p[i])<=0) top--;
		sta[++top]=p[i];
	}
	for(int i=1;i<top;i++) ans+=len(sta[i],sta[i+1]);
	ans+=len(sta[top],p[1]);
	printf("%.2lf\n",ans);
	return 0;
}

猜你喜欢

转载自www.cnblogs.com/BakaCirno/p/12562900.html
今日推荐