题面
题意
在平面上有n条直线,随机选择三条,其面积的期望大小是多少。
做法
很显然,面积的期望要转化为所有三角形的面积和除以
(
n
3
)
n\choose3
(3n),考虑计算三角形的面积和。
可以把三角形ABC的面积转化为(OA×OB+OB×OC+OC×OA)/2,这样只要分别计算这几个叉积的和即可。
经过观察不难发现,如果OA,OB的叉积会被计算,当且仅当A,B两点都在某条给出的直线上 ,因此我们可以枚举所有直线,计算直线上的交点两两的叉积和。
要注意叉积是有方向的,不满足交换律,这就意味着如果将点随意相乘会导致答案错误。所以要先对所有直线根据斜率排序,保证对于一个三角形上的三个点被逆时针加入,代码还是比较好理解的。
代码
#include<bits/stdc++.h>
#define db double
#define eps 1e-8
#define N 3010
using namespace std;
int n;
db x,y,sx,sy,ans;
struct Xn
{
db a,b,c;
bool operator < (const Xn &u) const
{
if(fabs(b)<eps) return 1;
if(fabs(u.b)<eps) return 0;
return a/b<u.a/u.b;
}
}xn[N];
int main()
{
int i,j;
cin>>n;
for(i=1;i<=n;i++) scanf("%lf%lf%lf",&xn[i].a,&xn[i].b,&xn[i].c);
sort(xn+1,xn+n+1);
for(i=1;i<=n;i++)
{
sx=sy=0;
for(j=i%n+1;j!=i;j=j%n+1)
{
x=(xn[j].c*xn[i].b-xn[i].c*xn[j].b)/(xn[i].a*xn[j].b-xn[j].a*xn[i].b);
y=(xn[j].c*xn[i].a-xn[i].c*xn[j].a)/(xn[j].a*xn[i].b-xn[i].a*xn[j].b);
//x,y表示i,j两条直线的交点
ans+=x*sy-y*sx;
sx+=x,sy+=y;
}
}
printf("%.12f",ans*3/n/(n-1)/(n-2));
}