【CF528E】Triangles 3000(計算幾何)

【CF528E】Triangles 3000(計算幾何)

題面

CF
平面上有若干條直線,保證不平行,不會三線共點。
求任選三條直線出來圍出的三角形的面積的指望。ios

題解

若是必定考慮直接計算這個三角形的面積,咱們很難不去弄出這三個交點。
咱們須要的是低於\(O(n^3)\)的複雜度,而\(O(n^3)\)的作法能夠直接暴力枚舉三條直線。
考慮向量計算面積的方法,對於一個在三角形\(\Delta ABC\)以外的點\(O\),咱們能夠有:
\[S\Delta ABC=\frac{1}{2}(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))\),那麼就能夠很開心的前綴和了。
注意爲了保證順序正確,須要把全部的直線按照極角提早排序。spa

#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 Vect{double x,y;}O,g[MAX];
struct Line{double 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;
}
相關文章
相關標籤/搜索