zoukankan      html  css  js  c++  java
  • 【题解】Triangles 3000 [CF528E]

    【题解】Triangles 3000 [CF528E]

    传送门:( ext{Triangles 3000 [CF528E]})

    【题目描述】

    给出 (n) ((n leqslant 3000)) 条直线的方程 (ax+by=c)(不会有三线交于一点的情况),求任选三条直线组成的三角形面积期望值。

    【分析】

    【学习笔记】计算几何全家桶

    (frac{sum S_{Delta ABC}}{C_{n}^{3}})

    ( ext{naive}) 的想法是暴力枚举三条直线计算交点,再乱搞算面积,似乎无法优化。

    考虑多边形面积的一般式:(S=frac{1}{2}sum_{iin[1,n]}vec{OP_i} imes vec{OP}_{i\%n+1}) (点集 ({P_1,P_2...P_n}) 呈逆时针排列,(O) 为平面上任意一点)

    放到三角形中就是 (S=frac{1}{2}(vec{OA} imes vec{OB}+vec{OB} imes vec{OC}+vec{OC} imes vec{OA}))

    即对于三角形的每条边 (EF)(设 (vec{EF}) 左方为三角形内部),(vec{OE}) 叉乘 (vec{OF}) 再求和。

    考虑枚举一条直线,设法统计该直线上所有需要计算的 “(vec{EF})” 。

    如果将其余的直线按极角从小到大依次加入,对于当前要加入的直线 (Line),设 (EF)(Line) 交点为 (P),前面已经加入的直线与 (Line) 交点的集合为 ({Q_1,Q_2...Q_m}),可知对于任意的 (Q_{iin[1,m]})(vec{Q_iP}) 均是需要计算的(自己画个图yy下,方向在三角形中均为逆时针,而且特殊情况都被题意中的“不会有三线交于一点”干掉了),所以答案需要累加 (sum_{i=1}^{m}OQ_i imes OP),将叉积式子拆开,得到 (sum_{i=1}^{m}({Q_i}_{x}*P_{y}-{Q_i}_{y}*P_{x})) (=(sum_{i=1}^{m}{Q_i}_{x})*P_{y}-(sum_{i=1}^{m}{Q_i}_{y})*P_{x}),直接记录下已经求出的 (Q_i) 坐标值总和即可。

    注意最后答案要除以 ((2C_{n}^{3}=frac{n(n-1)(n-2)}{3}))

    时间复杂度:(O(n^2))

    (没有卡精度好评)

    【Code】

    #include<algorithm>
    #include<cstdio>
    #include<cmath>
    #define LD double
    #define LL long long
    #define Re register int
    #define Vector Point
    using namespace std;
    const int N=3003;
    const LD eps=1e-8;
    inline int dcmp(LD a){return a<-eps?-1:(a>eps?1:0);}//处理精度
    struct Point{
        LD x,y;Point(LD X=0,LD Y=0){x=X,y=Y;}
        inline void in(){scanf("%lf%lf",&x,&y);}
        inline void print(){printf("%.3lf %.3lf
    ",x,y);}
    };
    inline void in(Re &x){
        int f=0;x=0;char c=getchar();
        while(c<'0'||c>'9')f|=c=='-',c=getchar();
        while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c^48),c=getchar();
        x=f?-x:x;
    }
    inline LD Dot(Vector a,Vector b){return a.x*b.x+a.y*b.y;}//【点积】
    inline LD Cro(Vector a,Vector b){return a.x*b.y-a.y*b.x;}//【叉积】
    inline LD Len(Vector a){return sqrt(Dot(a,a));}//【模长】
    inline Vector operator+(Vector a,Vector b){return Vector(a.x+b.x,a.y+b.y);}
    inline Vector operator-(Vector a,Vector b){return Vector(a.x-b.x,a.y-b.y);}
    inline Vector operator*(Vector a,LD b){return Vector(a.x*b,a.y*b);}
    inline Point cross_LL(Point a,Point b,Point c,Point d){//【两直线AB,CD的交点】
        Vector x=b-a,y=d-c,z=a-c;
        return a+x*(Cro(y,z)/Cro(x,y));//点A加上向量AF
    }
    inline int judge(Point a,Point L,Point R){//判断AL是否在AR右边
        return dcmp(Cro(L-a,R-a))>0;//必须严格以内
    }
    struct Line{
        Point a,b;LD k;Line(Point A=Point(0,0),Point B=Point(0,0)){a=A,b=B,k=atan2(b.y-a.y,b.x-a.x);}
        inline bool operator<(const Line &O)const{return dcmp(k-O.k)?dcmp(k-O.k)<0:judge(O.a,O.b,a);}//如果角度相等则取左边的
    }L[N];
    inline Point cross(Line L1,Line L2){return cross_LL(L1.a,L1.b,L2.a,L2.b);}//获取直线L1,L2的交点
    int n,a,b,c;LD x,y,ans;
    int main(){
    //    freopen("123.txt","r",stdin);
        in(n);
        for(Re i=1;i<=n;++i){
            in(a),in(b),in(c);
            if(!dcmp(a))L[i]=Line(Point(0,(LD)c/b),Point(1,(LD)c/b));//by=c -> y=c/b
            else if(!dcmp(b))L[i]=Line(Point((LD)c/a,0),Point((LD)c/a,1));//ax=c -> x=c/a
            else L[i]=Line(Point(0,(LD)c/b),Point(1,(LD)(c-a)/b));//ax+by=c -> y=(c-a*x)/b
        }
        sort(L+1,L+n+1);
        for(Re i=1;i<=n;++i){
            Point S,P;
            for(Re j=i<n?i+1:1;j!=i;j=j<n?j+1:1)//注意这里应该从i的下一个开始枚举
                P=cross(L[i],L[j]),ans+=Cro(S,P),S=S+P;
        }
        printf("%lf
    ",ans*3/n/(n-1)/(n-2));
    }
    
  • 相关阅读:
    开启ecstore隐藏的功能
    对接ECOS框架(含ecstore、ocs、erp等产品)的方法【其他系统请求ecos的api接口】
    shopex 网店系统基于云登录系统的信任登录设置
    怎样获取机器码
    windows 无法连接远程桌面
    ecos框架中data/ 目录下img*文件数量过多的问题
    mac 下brew解决php安装问题
    20140708 总结
    20140705 总结
    bzoj 2751
  • 原文地址:https://www.cnblogs.com/Xing-Ling/p/12679963.html
Copyright © 2011-2022 走看看