题目地址: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; }
时间: 2024-10-11 22:37:10