bzoj2829: 信用卡凸包(凸包)

传送门
题意:给 n n n A ∗ B A*B AB的矩形,其中每个矩形的四个角被改造成了半径为 r r r的四分之一 圆,问这些矩形的凸包周长。


思路:考虑求出圆心的凸包周长然后加上一个整圆的周长,证明很简单,略掉。
代码:

#include
#define ri register int
using namespace std;
const int N=10005;
struct pot{
    double x,y;
    friend inline pot operator+(const pot&a,const pot&b){return (pot){a.x+b.x,a.y+b.y};}
    friend inline pot operator-(const pot&a,const pot&b){return (pot){a.x-b.x,a.y-b.y};}
    friend inline double operator^(const pot&a,const pot&b){return a.x*b.y-a.y*b.x;}
    friend inline bool operator<(const pot&a,const pot&b){return a.x==b.x?a.y<b.y:a.x<b.x;}
    inline double mod(){return sqrt(x*x+y*y);}
}a[N<<2];
int n,tot=0,q[N<<2],top=0;
double A,B,R,ans,a1,a2,a3,a4,D;
const double pi=acos(-1.0),eps=1e-8;
inline void graham(){
    n=tot;
    sort(a+1,a+n+1);
    q[++top]=1;
    for(ri i=2;i<=n;++i){
        while(top>1&&((a[q[top]]-a[q[top-1]])^(a[i]-a[q[top-1]]))<=0)--top;
        q[++top]=i;
    }
    for(ri lim=top,i=n-1;i;--i){
        while(top>lim&&((a[q[top]]-a[q[top-1]])^(a[i]-a[q[top-1]]))<=0)--top;
        q[++top]=i;
    }
    for(ri i=1;i<top;++i)ans+=(a[q[i]]-a[q[i+1]]).mod();
}
int main(){
    scanf("%d%lf%lf%lf",&n,&A,&B,&R);
    A=A/2-R,B=B/2-R;
    a1=atan(A/B),a2=pi-a1,a3=pi+a1,a4=-a1;
    D=sqrt(A*A+B*B);
    ans=R*pi*2.0;
    for(ri i=1;i<=n;++i){
        double x,y,theta;
        scanf("%lf%lf%lf",&x,&y,&theta);
        a[++tot]=(pot){cos(theta+a1)*D+x,sin(theta+a1)*D+y};
        a[++tot]=(pot){cos(theta+a2)*D+x,sin(theta+a2)*D+y};
        a[++tot]=(pot){cos(theta+a3)*D+x,sin(theta+a3)*D+y};
        a[++tot]=(pot){cos(theta+a4)*D+x,sin(theta+a4)*D+y};
    }
    graham();
    printf("%.2lf",ans);
    return 0;
}

你可能感兴趣的:(#,凸包,#,计算几何)