P3829 [SHOI2012]信用卡凸包

传送门

弧线不好处理,考虑先求出直线的总长

画个图发现,把直线向内移动 $r$ 以后,所有直线构成了圆心点集的凸包

然后考虑弧线的长度,容易发现弧线的长度总是圆的周长,大概证明就是直线需要经过弧线才能拐弯

因为最后拐回来了,所以绕了一圈,那么弧线的弧度总和就是 $2\pi$

然后求所有圆心的凸包加上圆周长就好了

注意凸包的精度问题,我代码 $eps=1e-12$ 就会 $GG$,$eps=1e-5$ 就好了

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long ll;
typedef double db;
inline int read()
{
    int x=0,f=1; char ch=getchar();
    while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar(); }
    while(ch>='0'&&ch<='9') { x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); }
    return x*f;
}
const db eps=1e-5,pi=acos(-1.0);
const int N=1e5+7;
inline int dcmp(db x) { if(fabs(x)<eps) return 0; return x<0 ? -1 : 1; }
struct Poi {
    db x,y;
    Poi (db a=0,db b=0) { x=a,y=b; }
    inline Poi operator + (const Poi &tmp) const {
        return Poi(x+tmp.x,y+tmp.y);
    }
    inline Poi operator - (const Poi &tmp) const {
        return Poi(x-tmp.x,y-tmp.y);
    }
    inline bool operator < (const Poi &tmp) const {
        return dcmp(x-tmp.x)!=0 ? x<tmp.x : y<tmp.y;
    }
}P[N],st[N],T[5];
inline db Cross(Poi A,Poi B) { return A.x*B.y-A.y*B.x; }
inline db Dot(Poi A,Poi B) { return A.x*B.x+A.y*B.y; }
inline db Len(Poi A) { return sqrt(Dot(A,A)); }
inline bool cmp(const Poi &A,const Poi &B) { return dcmp(Cross(A,B))>0|| (dcmp(Cross(A,B))==0&&Len(A)<Len(B) ); }
inline Poi rotate(Poi A,db a) { return Poi(A.x*cos(a)-A.y*sin(a) , A.x*sin(a)+A.y*cos(a)); }
int n,tot;
inline void ins(db x,db y,db a)
{
    for(int i=1;i<=4;i++)
        P[++tot]=Poi(x,y)+rotate(T[i],a);
}
db Tubao()
{
    int Top=0;
    sort(P+1,P+tot+1);
    for(int i=tot;i>=1;i--) P[i]=P[i]-P[1];
    sort(P+1,P+tot+1,cmp);
    for(int i=1;i<=tot;st[++Top]=P[i],i++)
        while( Top>1 && dcmp(Cross(P[i]-st[Top-1],st[Top]-st[Top-1]))>=0 ) Top--;
    db res=Len(st[Top]-st[1]); for(int i=2;i<=Top;i++) res+=Len(st[i]-st[i-1]);
    return res;
}
int main()
{
    n=read(); db a,b,r,ans;
    scanf("%lf%lf%lf",&a,&b,&r); ans=pi*r*2; a-=r*2,b-=r*2;
    T[1]=Poi(b/2,a/2); T[2]=Poi(b/2,-a/2); T[3]=Poi(-b/2,a/2); T[4]=Poi(-b/2,-a/2);
    for(int i=1;i<=n;i++)
        scanf("%lf%lf%lf",&a,&b,&r),ins(a,b,r);
    printf("%.2lf\n",ans+Tubao());
    return 0;
}

 

posted @ 2019-09-01 10:42  LLTYYC  阅读(191)  评论(0编辑  收藏  举报