其他分享
首页 > 其他分享> > P3829 [SHOI2012]信用卡凸包

P3829 [SHOI2012]信用卡凸包

作者:互联网

思路

注意到结果就是每个信用卡边上的四个圆心的凸包周长+一个圆的周长

然后就好做了

注意凸包中如果存在叉积为0的点也要pop,否则可能会错。

几个简单的向量的式子

\[ a*b=(x_1y_1+ x_2y_2) \]
\[ a\times b=(x_1y_2- x_2y_1) \]
逆时针旋转\(\theta\)度
\[ x'=xcos\theta-ysin\theta\\ y'=xsin\theta+ycos\theta \]

代码

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
using namespace std;
struct Vec{
    double x,y;
    Vec(){};
    Vec(double xx,double yy){
        x=xx;
        y=yy;
    }
    double mul(Vec b){
        return x*b.x+y*b.y;
    }
    double cross(Vec b){
        return x*b.y-y*b.x;
    }
    Vec rev(double seta){
        return Vec(x*cos(seta)-y*sin(seta),x*sin(seta)+y*cos(seta));
    }
};
struct Point{
    double x,y;
    Point(){};
    Point(double xx,double yy){
        x=xx;
        y=yy;
    }
    Point operator + (Point b){
        return Point(x+b.x,y+b.y);
    } 
    Point operator + (Vec b){
        return Point(x+b.x,y+b.y);
    } 
    Vec operator - (Point b){//b-a a->b
        return Vec(b.x-x,b.y-y);
    }
    Point rev(Point b,double seta){//a 绕 b
        return b+((Point(x,y))-b).rev(seta);
    }
    double dist(Point a){
        return sqrt((x-a.x)*(x-a.x)+(y-a.y)*(y-a.y));
    }
};
struct Stack{
    int data[400100],topx=0;
    void push(int x){
        data[++topx]=x;
    }
    void pop(void){
        topx--;
    }
    int top(void){
        return data[topx];
    }
    int Setop(void){
        return data[topx-1];
    }
};
Point a[400100];
Stack S;
bool cmp(Point x,Point y){
    return (x-a[1]).cross(y-a[1])>0||((x-a[1]).cross(y-a[1])==0&&x.dist(a[1])>y.dist(a[1]));
}
int n,cnt;
double ax,bx,rx,ans=0;
int main(){
    scanf("%d",&n);
    scanf("%lf %lf %lf",&ax,&bx,&rx);
    for(int i=1;i<=n;i++){
        double x,y,seta;
        scanf("%lf %lf %lf",&x,&y,&seta);
        a[++cnt]=Point(x-bx/2+rx,y+ax/2-rx).rev(Point(x,y),seta);
        a[++cnt]=Point(x-bx/2+rx,y-ax/2+rx).rev(Point(x,y),seta);
        a[++cnt]=Point(x+bx/2-rx,y+ax/2-rx).rev(Point(x,y),seta);
        a[++cnt]=Point(x+bx/2-rx,y-ax/2+rx).rev(Point(x,y),seta);
    }
    // for(int i=1;i<=cnt;i++)
    //  printf("%lf %lf\n",a[i].x,a[i].y);
    int pos=1;
    for(int i=2;i<=cnt;i++)
        if(a[i].x<a[pos].x||(a[i].x==a[pos].x&&a[i].y<a[pos].y))
            pos=i;
    swap(a[1],a[pos]);
    sort(a+2,a+cnt+1,cmp);
    S.push(1);
    S.push(2);
    for(int i=3;i<=cnt;i++){
        while(S.topx>0&&(a[S.Setop()]-a[S.top()]).cross(a[S.Setop()]-a[i])<=0){
            S.pop();
        }
        S.push(i);
    }
    int tt=S.top();
    while(S.topx>1){
        ans+=a[S.top()].dist(a[S.Setop()]);
        S.pop();
    }
    ans+=a[S.top()].dist(a[tt]);
    ans+=2*acos(-1.0)*rx;
    printf("%.2lf\n",ans);
    return 0;
}

标签:return,seta,Point,int,double,凸包,Vec,SHOI2012,P3829
来源: https://www.cnblogs.com/dreagonm/p/10648046.html