标签:
题目地址:https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=4871
思路:将所有点上下左右四个点构成的集合求一遍凸包,边长不能直接计算(正确结果可能不为凸包)。
边长计算用下列式子:
x=fabs(a.x-b.x)
y=fabs(a.y-b.y)
c=fabs(x-y)+min(x,y)*sqrt(2)
(若答案最小则应尽量选择更多斜边)
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const double eps=1e-10;
const int maxn=4e5+50;
struct Point
{
double x,y;
Point(double x=0,double y=0):x(x),y(y) {}
};
typedef Point Vector;
Vector operator + (Vector A,Vector B)
{
return Vector(A.x+B.x,A.y+B.y);
}
Vector operator - (Point A,Point B)
{
return Vector(A.x-B.x,A.y-B.y);
}
Vector operator * (Vector A,double p)
{
return Vector(A.x*p,A.y*p);
}
int dcmp(double x)
{
if(fabs(x)<eps) return 0;
else return x<0?-1:1;
}
double Cross(Vector A,Vector B)
{
return A.x*B.y-A.y*B.x;
}
int cmp(Point a,Point b)
{
if(a.x==b.x) return a.y<b.y;
else return a.x<b.x;
}
int ConvexHull(Point* p,int n,Point* ch)
{
sort(p,p+n,cmp);
int m=0;
for(int i=0; i<n; i++)
{
while(m>1&&Cross(ch[m-1]-ch[m-2],p[i]-ch[m-2])<=0) m--;
ch[m++]=p[i];
}
int k=m;
for(int i=n-2; i>=0; i--)
{
while(m>k&&Cross(ch[m-1]-ch[m-2],p[i]-ch[m-2])<=0) m--;
ch[m++]=p[i];
}
if(n>1) m--;
return m;
}
double dist(Point a,Point b)
{
double x=fabs(a.x-b.x);
double y=fabs(a.y-b.y);
return fabs(x-y)+min(x,y)*sqrt(2);
}
int n;
Point ch[maxn],p[maxn];
int main()
{
while(scanf("%d",&n)==1)
{
int tot=0;
for(int i=0; i<n; i++)
{
double x,y;
scanf("%lf%lf",&x,&y);
p[tot++]=Point(x-1,y);
p[tot++]=Point(x+1,y);
p[tot++]=Point(x,y+1);
p[tot++]=Point(x,y-1);
}
memset(ch,0,sizeof(ch));
double ans=0.0;
int num=ConvexHull(p,tot,ch);
for(int i=0;i<num;i++)
ans+=dist(ch[i],ch[(i+1)%num]);
printf("%.4f\n",ans);
}
return 0;
}标签:
原文地址:http://blog.csdn.net/wang2147483647/article/details/52234974