和吴昊一起玩推理 Round 4 —— 随机化乎?蒙特卡洛!
这一个Round中,我只想阐述一点,在推理中,有些事情也不能完全确定 地来进行,在有必要的时候,必须引入一些随机的元素,这样虽然只能得到近似解,但是在时间效率上确实比确定解要高出许多。目前,这种思想已经成为了一种新 的方法,来解决一些NP难问题。因为,很多实际的问题是没有必要进行确定解的计算的。所以说,华科的院系领导对华科的老师进行审查的时候,也只会将命题人 员自己命的题目抽样出20%出来,观察其是否是各个参考资料上的原题目。
蒙特卡洛?神马东西?我们首先从地理上来理解,没有错,就是摩纳哥的赌城。这样,我们透过“赌博”这两个字推测到蒙特卡洛应该与随机化有关。那么,我们再 想想,恩,没有错,这就是美国的“曼哈顿计划”在实施的过程中,由冯--诺依曼亲自命名的。这种方法借助于概率这种独特的存在,使问题引入一定随机的元 素。
Monte Carlo方法的基本思想很早以前就被人们所发现和利用。早在17世纪,人们就知道用事件发生的“频率”来决定事件的“概率”。19世纪人们用投针试验的 方法来决定圆周率π。上个世纪40年代电子计算机的出现,特别是近年来高速电子计算机的出现,使得用数学方法在计算机上大量、快速地模拟这样的试验成为可 能。
(上面所说的投针实现指的是布丰投针实验)
考虑平面上的一个边长为1的正方形及其内部的一个形状不规则的“图形”,如何求出这个“图形”的面积呢?Monte Carlo方法是这样一种“随机化”的方法:向该正方形“随机地”投掷N个点有M个点落于“图形”内,则该“图形”的面积近似为M/N。
利用一些变化的分布,蒙特卡洛方法会发展为一些变种,比如,如果将均匀分布变为超均匀分布,或者几何分布变为超几何分布的话,一些仿蒙特卡洛的方法就会出现了。这里就不一一描述了,无论用什么蒙特卡洛的变种,其目的都是一样的,利用近似解来换取比较低的时间复杂度。
最后,我们看一个例子,蒙特卡洛可以用在任意确定性的问题上,甚至可以用来基于一定概率地来判断两个集合是否是相等的,源码如下:
2 #include<stdlib.h>
3 #include<math.h>
4 #include<time.h>
5
6 bool Majority(int *S,int *T,int n)
7 {
8 int i,j,x;
9 bool k;
10 time_t t;
11
12 //系统利用时间制造一个“真实”的随机数,取模得到一个检验的下标值
13 srand((unsigned)time(&t));
14 i=rand()%(n)-1;
15 x=S[i];
16 k=0;
17 for(j=0;j<n;j++)
18 {
19 if(T[j]==x)
20 k=1;
21 }
22 return k;
23 }
24
25 bool MajorityMC(int *S,int *T,int n)
26 {
27 int k;
28 double e;
29
30 //这里采用一定的参数确定采样的次数
31 e=0.00001;
32 k=(int)ceil(log(1/e));
33 for(int i=1;i<=k;i++)
34 {
35
36 //只要有一个不满足的情况就是不可以的!!!
37 if(!Majority(S,T,n))
38 return 0;
39 }
40 return 1;
41 }
42
43 int main()
44 {
45 int i,n;
46
47 //这里我们开两个100000整型变量空间的数组
48 int S[100000],T[100000];
49 scanf("%d",&n);
50 for(i=0;i<n;i++)
51 scanf("%d",&S[i]);
52 for(i=0;i<n;i++)
53 scanf("%d",&T[i]);
54
55 //这里,采用蒙特卡洛方法进行模拟
56 if(MajorityMC(S,T,n))
57 printf("YES");
58 else printf("NO");
59 return 0;
60 }
61