EOJ Monthly 2018.12 B. 清点星辰(蒙特卡洛模拟)

B. 清点星辰

单测试点时限: 2.0 秒

内存限制: 512 MB

“夜里,
你要抬头仰望满天的星星。
我那颗实在太小了,
我都没法指给你看它在哪儿。”

这样倒也好,我的星星,对你来说就是满天星星中的一颗。

所以,你会爱这满天的星星…所有的星星都会是你的朋友。

即使只能通过狭小的洞口,在楼宇的夹缝中仰望布满星辰的天空,你还是无法割舍对它的期待。

星星数不胜数,但你还是不厌其烦地清点他们。日复一日,终于在今天,你把他们都数清楚了。

于是你又开始找别的事情做了。你开始计算他们两两之间的最近距离。

你仰望星空的洞口是一个 1×1 的正方形,每天,星辰的位置都会发生变化,具体地说,每天都会有 n 个星辰随机地散落在这个正方形内的某个坐标上(每个点横纵坐标满足独立同分布 U(0,1))。

每天的距离都在变化,所以现在你只想知道他们两两之间最近距离的期望是多少。

输入

输入一个整数 n (2≤n≤109) ,表示星辰的数量。

输出

一行一个小数,输出答案。绝对误差在 10−3 内会被视为正确。

样例

input

2

output

0.521405

input

3

output

0.3055302430

提示

对于某连续性随机变量 X,若其取值范围为 Ω,其概率密度函数为 p(x),则其期望定义为 E(X)=∫Ωxp(x)。若要求关于 X 的函数 f(X) 的期望,则 E(f(X))=∫Ωf(x)p(x)。

该式子可以在多变量上进行推广,如果有两个随机变量 X, Y,则关于 X,Y 的函数 f(X,Y) 的期望可以定义为 E(f(X,Y))=∫Ωf(x,y)p(x,y),其中 p(x,y) 是 x,y 的联合概率密度函数。在 X 和 Y 独立时,p(x,y)=p(x)p(y)

在本题中,所有变量的概率密度函数都是 p(x)=1,0<x<1。故所求式可以写为:

∫10∫10⋯∫102nmin1≤i<j≤n(xi−xj)2+(yi−yj)2−−−−−−−−−−−−−−−−−√ dx1dy1dx2dy2⋯dxndyn

在 n=2 时,该式可以化简为:

∫10∫10∫10∫10(x1−x2)2+(y1−y2)2−−−−−−−−−−−−−−−−−−√ dx1dy1dx2dy2

求出该积分的值约为 0.521405。

在 n>2​ 的情形下,由于式子中有 min,积分式十分复杂,很有可能没有解析解。在定积分不可行的情况下,可以采用数值逼近的方法近似计算给定的定积分值,这种方法称为数值积分。借助于电子计算设备,数值积分可以快速而有效地计算复杂的积分。数值积分常用的方法包括矩形法、辛普森积分法等。更多有关数值积分的数学原理和算法介绍,读者可以自行阅读维基百科

题目复制有变化,原地址:https://acm.ecnu.edu.cn/contest/125/problem/B/#report10 

题意:不说了,都能看懂。

题解:蒙卡洛模拟,说白了就是随机数。看代码:

#include <iostream>
#include <cstdlib>
#include <cmath>
#include <ctime>
using namespace std;
const int MAX = 1e6;
double x[MAX],y[MAX];
int main(){
	 int n,a,b;
	 a=0;
	 b=1;
	 cin >> n;
	 if(n>=888){//n很大后基本就是0,可以跑一下试试,因为开不了1e9的数组而且超时,只能这样,注意:数据误差要求0.001
	 	cout << 0.000000 << endl;
	 	return 0;
	 }
	 double ans=0;
	 int w=1e7/n/n;//保证复杂度为1e7的情况下随机次数最多,就是在不超时情况下,随机次数竟可能多,这样误差就小
	 srand(time(NULL));//以时间种子,防止被卡
	 for (int i = 1; i <= w;i++){
	 	double minn=520;
	 	for (int j = 1; j <= n;j++){
	 		x[j]=((double)rand()/RAND_MAX)*(b-a)+a;//产生a——b之间的随机数
	 		y[j]=((double)rand()/RAND_MAX)*(b-a)+a;
	 		for (int k = 1; k < j;k++) {
				minn=min(minn,sqrt((x[j]-x[k])*(x[j]-x[k])+(y[j]-y[k])*(y[j]-y[k])));
			}
		 }
	 	ans+=minn;//每次情况求和
	 }
	 printf("%.6f\n",ans/w);//求平均数
	return 0;
}

猜你喜欢

转载自blog.csdn.net/lgz0921/article/details/85030140