UVALive - 6859 Points
题意:给你n个点,然后在方格纸上只能选取边或者对角线,求围住所有点的最小周长
题解:根据样例可以发现一个规律,你把制定点的上下左右点都标出来,会发现这是围城一个点的最小距离,这样把所有的点都标记出来,求一下凸包(本人习惯kuangbin板子,但忘了凸包的时间复杂度了,以为会超时,谁知道没有),凸包的算法求出来的是点,这些点被压栈了,在计算距离的时候,只需要按照题目意思,尽量多选择对角线,连起来就可以了。
#include <bits/stdc++.h> using namespace std; const double eps=1e-8; int sgn(double x) { if(fabs(x)<eps) return 0; if(x<0) return -1; else return 1; } struct point { double x,y; point (){} point (double _x,double _y) { x=_x,y=_y; } point operator -(const point &b)const { return point(x-b.x,y-b.y); } double operator ^(const point &b)const { return x*b.y-y*b.x; } double operator *(const point &b)const { return x*b.x+y*b.y; } }; const int maxn=1e5+5; point List[4*maxn]; int Stack[4*maxn],top; double dist(point p0,point p1) { return (double)sqrt((p0.x-p1.x)*(p0.x-p1.x)+(p0.y-p1.y)*(p0.y-p1.y)); } bool cmp(point p1,point p2) { double tmp = (p1-List[0])^(p2-List[0]); if(sgn(tmp) > 0)return true; else if(sgn(tmp) == 0 && sgn(dist(p1,List[0]) - dist(p2,List[0])) <= 0) return true; else return false; } void Graham(int n) { point p0; int k = 0; p0 = List[0]; for(int i = 1; i < n; i++){ if((p0.y>List[i].y)||(p0.y==List[i].y&&p0.x>List[i].x)){ p0 = List[i]; k = i; } } swap(List[k],List[0]); sort(List+1,List+n,cmp); Stack[0] = 0; Stack[1] = 1; top = 2; for(int i = 2; i < n; i++){ while(top > 1 &&sgn((List[Stack[top-1]]-List[Stack[top-2]])^(List[i]-List[Stack[top-2]]))<=0) top--; Stack[top++] = i; } } point as[maxn]; double dist2(point p0,point p1) { double as=fabs(p0.x-p1.x); double qw=fabs(p0.y-p1.y); return fabs(as-qw)+min(as,qw)*sqrt(2); } int main() { int n; while(~scanf("%d",&n)) { double t1,t2; memset(as,0,sizeof(as)); for(int i=0;i<n;i++){ scanf("%lf%lf",&t1,&t2); as[i]=point(t1,t2); } for(int i=0;i<n;i++){ List[4*i+0]=point(as[i].x-1,as[i].y); List[4*i+1]=point(as[i].x+1,as[i].y); List[4*i+2]=point(as[i].x,as[i].y+1); List[4*i+3]=point(as[i].x,as[i].y-1); } n*=4; Graham(n); double res=0.0; for(int i=0; i<top-1; i++) res+=dist2(List[Stack[i]],List[Stack[i+1]]); res+=dist2(List[Stack[0]],List[Stack[top-1]]); printf("%.4f\n",res); } return 0; } /* 1 0 0 2 1 1 1 2 */