E - 蹲在牆角畫圈圈的愚人王
Time Limit: 3000/1000MS (Java/Others) Memory Limit: 65535/65535KB (Java/Others)
愚人王發現自己也就是條鹹魚了,只能搞(出)搞(出)套路題了。所以膜拜了下final柱後,默默的蹲在牆角畫圈圈去了.....
他在一個X*Y的矩形框框裏畫了n個圈圈(圓),然後無聊的向這個矩形中丟石子玩.....
突然,他靈(臨)光(時)一(腦)閃(抽)!
他突然非常想知道,如果每次丟一個石子得到的分數爲被覆蓋的圓的數量的平方的話,那麼得到的分數的數學期望是啥?!
嗯,他假設:石子是無限小的一個個的點;X,Y,圓的座標和半徑都是整數;所有的圓都在矩形框框中。
腦補半響後,他驚呼:“這道題太難了,根本不會做呀......“
機智的您,請幫愚人王解決一下這個問題吧.....
Input
第一行,n表示圈圈的個數。
0<=n<=1000;
第二行,X,Y
1<=X,Y<=1000
後面n行,每行三個整數x y r表示第i個圓的圓心座標和半徑。保證圓在矩形內部。
Output
一行,表示分數的期望。沒有spj,結果請保留三位小數.
解題思路:
解題思路:
期望=每個區域覆蓋次數的平方*(區域面積/總面積);
利用二次項展開,例如:(A+B+C)^2=(A*A+B*B+C*C+A*B+B*A+A*C+C*A+B*C+C*B);
乘號代表面積求交;我們可以發現這樣計算每個區域的面積正好被計算了被覆蓋次數的平方次;
代碼:#include<bits/stdc++.h>
using namespace std;
struct node{
int x,y,r;
}cir[1001];//保存圓的圓心座標,半徑;
double cross(int x1,int y1,int r1,int x2,int y2,int r2)//求圓面積交,其中用到餘弦定理,算出兩個扇形的和減去多邊形的面積;
{
double d=pow(x1-x2,2)+pow(y1-y2,2);
if(d<=pow(r1-r2,2))
{
return pow(min(r1,r2),2)*M_PI;
}
else if(d>pow(r1-r2,2)&&d<pow(r1+r2,2))
{
double m1=(r1*r1+d-r2*r2)/(2*r1*sqrt(d));
double m2=(r2*r2+d-r1*r1)/(2*r2*sqrt(d));
double s1=acos(m1)*r1*r1;
double s2=acos(m2)*r2*r2;
double s3=sqrt(d)*r1*sin(acos(m1));
return s1+s2-s3;
}
else
return 0;
}
int main()
{
int n,x,y,i,j;
double sum=0;
scanf("%d%d%d",&n,&x,&y);
for(i=0;i<n;i++)
scanf("%d%d%d",&cir[i].x,&cir[i].y,&cir[i].r);
for(i=0;i<n;i++)
for(j=0;j<n;j++)
sum+=cross(cir[i].x,cir[i].y,cir[i].r,cir[j].x,cir[j].y,cir[j].r);//枚舉求交;
printf("%.3f",sum/(x*y));
}
原本還想用圓的離散化的,那樣太麻煩了,其實這樣做30+行搞定;