题意:建围墙将n个点围起来,围墙与点的距离不小于L,求围墙长度;
思路:凸包周长+L为半径的圆周长;凸包即为覆盖一个点集所有点的最小区域;
#include<cstdio> #include<cstring> #include<cmath> #include<algorithm> using namespace std; const double epsi=1e-10; const double pi=acos(-1.0); const int maxn=10005; struct point{ double x,y; point(){} point(double xx,double yy):x(xx),y(yy){} point operator -(const point &op2)const{ return point(x-op2.x,y-op2.y); } double operator ^(const point &op2) const{ //两个点向量的叉积 return x*op2.y-y*op2.x; } }; inline int sign(const double &x){ if(x>epsi) return 1; if(x<-epsi) return -1; return 0; } inline double sqr(const double &x){ return x*x; } inline double mul(const point &p0,const point &p1,const point &p2){ return (p1-p0)^(p2-p0); } inline double dis2(const point &p0,const point &p1){ return sqr(p0.x-p1.x)+sqr(p0.y-p1.y); } inline double dis(const point &p0,const point &p1){ return sqrt(dis2(p0,p1)); } int n,l; //n个顶点,最近距离为l point p[maxn],convex_hull; //多边形顶点序列为p[],最低位置的点为convex_hull inline bool cmp(const point &a,const point &b){ //相对最低点,各点极角从小到大,距离从近到远排序 return sign(mul(convex_hull,a,b))>0||sign(mul(convex_hull,a,b))==0&&dis2(convex_hull,a)<dis2(convex_hull,b); } int convex(point *a,int n,point *b){ //计算含n个点的点集a的凸包b if(n<3) printf("Wrong in Line %d\n",__LINE__); //顶点数小于3,输出失败信息 for(int i=1;i<n;i++) //计算最低点convex_hull if(sign(a[i].x-a[0].x)<0||sign(a[i].x-a[0].x)==0&&sign(a[i].y-a[0].y)<0) swap(a[0],a[i]); convex_hull=a[0]; sort(a,a+n,cmp); //按极角和距离排序 int newn=2; b[0]=a[0];b[1]=a[1]; //a[0],a[1]入栈 for(int i=2;i<n;i++){ while(newn>1&&sign(mul(b[newn-1],b[newn-2],a[i]))>=0) --newn; //弹出栈顶所有未左转指向扫描顶点i的元素 b[newn++]=a[i]; //顶点i入栈 } return newn; //栈顶指针 } int main(){ scanf("%d%d",&n,&l); for(int i=0;i<n;i++) scanf("%lf%lf",&p[i].x,&p[i].y); n=convex(p,n,p); p[n]=p[0]; //首尾相连 double ans=0; for(int i=0;i<n;i++) ans+=dis(p[i],p[i+1]); //累计凸包边长 ans+=2*pi*l; printf("%.0f\n",ans); return 0; }
时间: 2024-12-28 16:20:48