CF528ETriangles 3000(计算几何)

Posted cjyyb

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CF528ETriangles 3000(计算几何)相关的知识,希望对你有一定的参考价值。

【CF528E】Triangles 3000(计算几何)

题面

CF
平面上有若干条直线,保证不平行,不会三线共点。
求任选三条直线出来围出的三角形的面积的期望。

题解

如果一定考虑直接计算这个三角形的面积,我们很难不去弄出这三个交点。
我们需要的是低于\(O(n^3)\)的复杂度,而\(O(n^3)\)的做法可以直接暴力枚举三条直线。
考虑向量计算面积的方法,对于一个在三角形\(\Delta ABC\)之外的点\(O\),我们可以有:
\[S\Delta ABC=\frac12(OA\times OB+OB\times OC+OC\times OA)\]
这个证明不难,画图把每一部分的面积表示出来就很简单了。
接下来枚举一条直线,剩下点按照极角顺序依次加入,然后这个贡献可以拆成三个部分,而我们只算都在枚举的直线上的交点的贡献,在其他直线上的可以在其他时候算。
于是要求的就是这条直线和枚举的直线的交点与前面所有直线与枚举的直线的交点与\(O\)构成的向量的叉积。
叉积是:\((x1,y1)\times (x2,y2)=x1*y2-x2*y1\)
于是得到:\((x1,y1)\times (x2,y2)+(x1,y1)\times (x3,y3)=x1*(y2+y3)-y1*(x2+x3)\)
这个东西显然等于\((x1,y1)\times ((x2,y2)+(x3,y3))\),那么就可以很开心的前缀和了。
注意为了保证顺序正确,需要把所有的直线按照极角提前排序。

#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
#define MAX 3030
inline int read()

    int x=0;bool t=false;char ch=getchar();
    while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    if(ch=='-')t=true,ch=getchar();
    while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
    return t?-x:x;

int n;double ans;
struct Vectdouble x,y;O,g[MAX];
struct Linedouble a,b,c,ang;L[MAX];
bool operator<(Line a,Line b)return a.ang<b.ang;
Vect Intersection(Line a,Line b)

    if(fabs(a.a)>1e-9)
    
        double y=(b.c*a.a-a.c*b.a)/(a.b*b.a-a.a*b.b);
        double x=-(a.c+a.b*y)/a.a;
        return (Vect)x,y;
    
    else
    
        double x=(b.c*a.b-a.c*b.b)/(a.a*b.b-a.b*b.a);
        double y=-(a.c+a.a*x)/a.b;
        return (Vect)x,y;
    

double Cross(Vect a,Vect b)return a.x*b.y-a.y*b.x;
Vect operator-(Vect a,Vect b)return (Vect)a.x-b.x,a.y-b.y;
Vect operator+(Vect a,Vect b)return (Vect)a.x+b.x,a.y+b.y;
bool cmp(Vect a,Vect b)return Cross(a,b)>=0;
int main()

    n=read();O=(Vect)1e7,1e7;
    for(int i=1;i<=n;++i)
    
        L[i].a=read(),L[i].b=read(),L[i].c=-read();
        double x,y;
        if(fabs(L[i].b)>1e-7)x=1,y=-L[i].a/L[i].b;
        else y=1,x=-L[i].b/L[i].a;
        L[i].ang=atan2(y,x);
    
    sort(&L[1],&L[n+1]);
    /*
    for(int i=1;i<=n;++i)
        for(int j=i+1;j<=n;++j)
            for(int k=j+1;k<=n;++k)
            
                Vect g[3];
                g[0]=Intersection(L[i],L[j]);
                g[1]=Intersection(L[j],L[k]);
                g[2]=Intersection(L[k],L[i]);
                ans-=(Cross(g[0],g[1])+Cross(g[1],g[2])+Cross(g[2],g[0]));
            
    ans/=1.0*n*(n-1)*(n-2)/3;
    printf("%.10lf\n",ans);ans=0;
    */
    for(int i=1;i<=n;++i)
    
        Vect s=(Vect)0,0;
        for(int j=i%n+1;j!=i;j=j%n+1)
        
            Vect a=Intersection(L[i],L[j]);
            ans+=Cross(s,a);s=s+a;
        
    
    ans/=1.0*n*(n-1)*(n-2)/3;
    printf("%.10lf\n",ans);
    return 0;

以上是关于CF528ETriangles 3000(计算几何)的主要内容,如果未能解决你的问题,请参考以下文章

CF528D Fuzzy Search

CF1059D Nature Reserve (精度处理,计算几何,二分)

[CF528D]Fuzzy Search

CF528D Fuzzy Search

CF_528D

[M数学] lc528. 按权重随机选择(前缀和+数学+概率+几何概型+好题)