SHOI2012 信用卡凸包

Posted zmyzmy

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SHOI2012 信用卡凸包相关的知识,希望对你有一定的参考价值。

题意:

题目链接
题目大意:
给出n个四角为pi/4的圆弧的类矩形,求它们凸包的周长

思路:

乍看似乎没有思路,但注意到r=0时求的是一个裸的凸包
考虑当r不等于0时,我们先按之前的方法求出凸包周长
然后对于每个拐点求其角度,而后求出这段圆弧长,累加即可。。。

for(int i=1;i<=m;++i)
{
    ans+=(q[i]-q[i+1]).dist();
    double cs=((q[i]-q[i+1])*(q[i+2]-q[i+1]))/(q[i]-q[i+1]).dist()/(q[i+1]-q[i+2]).dist();
        //点乘a*b=|a||b|cos<a,b>(a,b为向量)
    double dg=pi-acos(cs);
    ans+=dg*r;
}

最后提交AC后看了遍题解,发现圆弧累加后的总长度就是一个整圆的周长,直接加就可以了。

for(int i=1;i<=m;++i)
    ans+=(q[i]-q[i+1]).dist();
ans+=2*pi*r;

注意事项:

pi指180度,而不是360度(这种错只有我才犯吧。。。)

code:

#include<bits/stdc++.h>
using namespace std;
const int N=1e4+5;
const double eps=1e-7;
const double pi=3.1415926535898;
int n,m,cnt,per[N<<2];
double a,b,r;
struct point{double x,y;double dist(){return sqrt(x*x+y*y);}}p[N<<2],q[N<<2];
point operator+(point x,point y){return (point){x.x+y.x,x.y+y.y};}
point operator-(point x,point y){return (point){x.x-y.x,x.y-y.y};}
double operator*(point x,point y){return x.x*y.x+x.y*y.y;}
double operator^(point x,point y){return x.x*y.y-x.y*y.x;}
inline double readin(){double x;scanf("%lf",&x);return x;}
inline double lfabs(double x){return x<-eps?-x:x;}
inline point rot(point pp,double dg)
{
    return (point){pp.x*cos(dg)-pp.y*sin(dg),pp.y*cos(dg)+pp.x*sin(dg)};
}
struct cmpfunctor{
    inline bool operator()(int x,int y)
    {
        double dit=(p[x]-p[1])^(p[y]-p[1]);
        if(lfabs(dit)>eps) return dit>eps;
        return (p[x]-p[1]).dist()<(p[y]-p[1]).dist();
    }
};
inline void Graham()
{
    for(int i=2;i<=cnt;++i)
        if(p[i].x-p[1].x<-eps||(lfabs(p[i].x-p[1].x)<eps&&p[i].y-p[1].y<-eps))
            swap(p[1],p[i]);
    for(int i=1;i<=cnt;++i)per[i]=i;
    sort(per+2,per+cnt+1,cmpfunctor());
    q[++m]=p[1];
    for(int i=2;i<=cnt;++i)
    {
        int j=per[i];
        while(m>1&&((p[j]-q[m-1])^(q[m]-q[m-1]))>-eps) --m;
        q[++m]=p[j];
    }
    q[m+1]=q[1];q[m+2]=q[2];
}
inline double C()
{
    double ans=0;
    for(int i=1;i<=m;++i)
        ans+=(q[i]-q[i+1]).dist();
    return ans+2.0*pi*r;
}
int main()
{
    scanf("%d",&n);
    scanf("%lf%lf%lf",&a,&b,&r);
    for(int i=1;i<=n;++i)
    {
        point pt;scanf("%lf%lf",&pt.x,&pt.y);
        point ne=(point){pt.x+b/2.0-r,pt.y+a/2.0-r};
        point nw=(point){pt.x-b/2.0+r,pt.y+a/2.0-r};
        double dg=readin();
        p[++cnt]=rot(ne-pt,dg)+pt;p[++cnt]=rot(nw-pt,dg)+pt;
        point ps=pt+pt-p[cnt];p[++cnt]=ps;
        ps=pt+pt-p[cnt-2];p[++cnt]=ps;
    }
    Graham();
    printf("%.2lf",C());
    return 0;
}

以上是关于SHOI2012 信用卡凸包的主要内容,如果未能解决你的问题,请参考以下文章

Luogu-3829 [SHOI2012]信用卡凸包

P3829 [SHOI2012]信用卡凸包

P3829 [SHOI2012]信用卡凸包

bzoj2829 信用卡凸包

P3833 [SHOI2012]魔法树

[SHOI2012]魔法树