UVALive 2453 Wall (凸包)
题意:给你一个多边形的城堡(多个点),使用最短周长的城墙将这个城堡围起来并保证城墙的每个点到城堡上的每个点的距离都不小于l
题解:因为两点间的直线一定比折线短,所以这样做
先使用所有点求得一个凸包,接着凸包每条边外移l长度,再在每相邻两条线间画一个半径为l的圆弧(想一想为什么)
因为凸包上每个点与平移后对应点相连会垂直于凸包对应的边,所有圆弧的每个角与对应多边形的内角互补
又因为多边形外角和为360度,所有可以看做凸包多加一个半径为l的圆
#include<set> #include<map> #include<queue> #include<stack> #include<cmath> #include<vector> #include<string> #include<cstdio> #include<cstring> #include<iomanip> #include<stdlib.h> #include<iostream> #include<algorithm> using namespace std; #define eps 1E-8 /*注意可能会有输出-0.000*/ #define sgn(x) (x<-eps? -1 :x<eps? 0:1)//x为两个浮点数差的比较,注意返回整型 #define cvs(x) (x > 0.0 ? x+eps : x-eps)//浮点数转化 #define zero(x) (((x)>0?(x):-(x))<eps)//判断是否等于0 #define mul(a,b) (a<<b) #define dir(a,b) (a>>b) typedef long long ll; typedef unsigned long long ull; const int Inf=1<<28; const ll INF=1ll<<60; const double Pi=acos(-1.0); const int Mod=1e9+7; const int Max=10010; struct Point { double x,y; Point(double x=0,double y=0):x(x),y(y) {}; inline int read() { scanf("%lf%lf",&x,&y); } inline Point operator-(const Point& a)const { return Point(x-a.x,y-a.y); } inline bool operator<(const Point& a)const { return sgn(x-a.x)<0||(zero(x-a.x)&&sgn(y-a.y)<0); } inline bool operator==(const Point& a)const { return zero(a.x-x)&&zero(a.y-y); } inline bool operator!=(const Point& a)const { return !(zero(a.x-x)&&zero(a.y-y)); } }; typedef Point Vector; double Cross(Vector A,Vector B) { return A.x*B.y-A.y*B.x; } double Dis(Point A,Point B) { return sqrt((A.x-B.x)*(A.x-B.x)+(A.y-B.y)*(A.y-B.y)); } int ConvexHull(Point* p,int n,Point* convex) { sort(p,p+n); int m=1; for(int i=0; i<n; ++i) if(p[i]!=p[m-1]) p[m++]=p[i]; n=m; m=0; for(int i=0; i<n; ++i) { while(m>1&&Cross(convex[m-1]-convex[m-2],p[i]-convex[m-2])<0) m--; convex[m++]=p[i]; } int k=m; for(int i=n-1; i>=0; --i) { while(m>k&&Cross(convex[m-1]-convex[m-2],p[i]-convex[m-2])<0) m--; convex[m++]=p[i]; } if(n>1) m--; return m; } Point convex[Max],wall[Max]; double Solve(int n,double l) { double perimeter=0; int m=ConvexHull(wall,n,convex); for(int i=1; i<=m; ++i) { perimeter+=Dis(convex[i-1],convex[i%m]); } return perimeter+l*Pi*2; } int main() { int t,n; double l; scanf("%d",&t); while(t--) { scanf("%d %lf",&n,&l); for(int i=0; i<n; ++i) { wall[i].read(); } printf("%.0f\n",Solve(n,l)); if(t) printf("\n"); } return 0; }