零、概述

大家好,我是 NEYC 1702 GGN。高二下学期,1702班 所采用的随机排座程序是我编写的,虽然我在这方面投入了不少精力,但是我的程序还是暴露出了很多问题。经过一段时间的反思,我决定再一次修改我的排座程序。这一次的拍做程序中,我将采用理论上完全符合古典概型的随机生成程序。另一方面,我也会对 《2019.4.26 排座协议》 进行一系列的修改调整。

不同于前几次对于排座程序的 “实践性” 、“感性”的修改,这次我将以 数学理论 为基础证明我的排座程序的随机性。由于我的数学水平十分有限,非常欢迎老师们、同学们、家长们指出下文中不合理的地方,我会尽快对这些错误进行修正。

一、数学模型的构建

什么是 “一个合法的排座方案”?

班级中每次参与排座的人数是不确定的,这个我们的排座模型的建立带来了很大的困难。因此,在排座模型中,我们规定,1702班每次参与排座的同学数量为 30 人,其中女生 5 人,男生25人。为了方便起见,下文中,我们用编号1 ~ 5来表示女生,编号6 ~ 30表示男生。显然,编号的分配并不影响事件发生的概率(在此不作赘述)。根据惯例,我们规定,女生必须被安排在班级的前三行。

“一个合法的排座方案” 是 一个满足下列条件的矩阵

  1. 行数为5,列数为6
  2. 矩阵中的每一个元素 a 都满足 a∈{1,2,3,...,30}a \in \{1, 2, 3, ..., 30\}a∈{1,2,3,...,30}
  3. 矩阵中不存在两个位置不同但数值相同的元素
  4. 如果属于集合{1,2,3,4,5}\{1, 2, 3, 4, 5\}{1,2,3,4,5}的任意一个元素 存在于矩阵中,那么该元素一定存在于矩阵的前三行。

这四条定义是十分容易理解的,在此不做赘述。下文中我们将用集合 UUU来表示所有合法排座方案组成的集合。

何谓 “生成程序符合古典概型”

符合古典概型就是指:程序生成出任何两种不同的座位图的 概率 是相同的。

即: ∀E,F∈U,E≠F⇒P(E)=P(F)\forall E,F \in U,E\neq F \Rightarrow P(E)=P(F)∀E,F∈U,E̸​=F⇒P(E)=P(F)

二、矩阵的生成

总合法方案数(下文中用符号 Card(U)Card(U)Card(U) 表示)

Card(U)=A185A2525≈2.658001×1028Card(U)=A_{18}^5 A_{25}^{25} \approx 2.658001 \times 10^{28}Card(U)=A185​A2525​≈2.658001×1028

其中AmnA_m^nAmn​表示 从m个不同元素中抽取n个不同元素的排列数。

解释:从前三排的18个座位中抽取5个座位依次分配给每个女生,然后所有的男生的随机占据当前未被占据的25个位置。

随机排列算法

对于一个长度为n的数列arr我们给出了这样一种随机排列的方式:我们利用系统自带的随机数生成器为数列中的每一个元素 生成一个属于[0,230)[0, 2^{30})[0,230)范围内的随机整数(即程序中的函数RND)作为它的权值,然后把数列按照权值进行排序,得到的新数列即为随机打乱后的数列。可以证明,如果计算机生成的随机权值是完全随机的,那么得到的数列就是随机打乱的。(其实应该证明一下的,不过我比较懒。。)

namespace Permutation { /// 用于生成随机排列 struct Pair {int val, rght; /// val 实际值, rght 权值 } ns[30 + 3];bool Cmp(const Pair& p1, const Pair& p2) { /// 用于随机排列 return p1.rght < p2.rght; /// 按照权值升序排列 }void MakeRndPermutation(int* arr, int n) { /// 构造随机排列 memset(ns, 0x00, sizeof(ns));for(int i = 1; i <= n; i ++) {ns[i] = (Pair){arr[i], RND()}; /// 载入数据 }sort(ns+1, ns+n+1, Cmp); /// 随机排列 for(int i = 1; i <= n; i ++) {arr[i] = ns[i].val; /// 存回数据 }}
}

随机排座算法

我们可以利用上文中提及的随机排列算法去实现随机排座的过程:

最开始的时候,我们定义了一个5行6列的矩阵,它的每一个位置上的元素都是0。

先构造一个长度为18的数列,这个数列中的前五个元素为1~ 5,其余元素都为零。然后将这个数列打乱,将打乱后的数列中,下标为1 ~ 6的六个元素 从左到右依次填充到矩阵的第一行的位置上,同理,下标为7 ~ 12 的六个元素 从左到右一次填充到矩阵的第二行的位置上,下标为 13 ~ 18 的六个元素 从左到右依次填充到矩阵的第三行的位置上。这样就完成了对女生座位的安排。然后我们再构造另一个长度为25的数列,其下标为k的位置上的数值为k+5。然后再对这个数列也进行随机打乱,并将这个数列中的元素 按照从矩阵第一行到矩阵第五行的顺序依次填充到矩阵中每一个当前数值为0的位置上。

namespace Graph { /// 生成座位图 /// 学号 1~30, 其中 1~5 为女生, 6~30 为男生/// 女生必须坐在前三排 int store[7][7]; /// 6 * 6 的座位图 int posx[30 + 3], posy[30 + 3]; /// 每个同学的位置 void Construct() { /// 构造一个座位图 int arr[30 + 3] = {}, tmp = 1;memset(store, 0x00, sizeof(store)); /// 注意数据清零 /// posx posy 理论上会被完全覆盖, 再次不再清零 /// 安排女生 for(int i = 1; i <= 5; i ++) {arr[i] = i;}Permutation::MakeRndPermutation(arr, 18); /// 随机排列 for(int i = 1; i <= 18; i ++) {store[(i-1)/6 + 1][(i-1)%6 + 1] = arr[i];//printf("set %d at %d, %d\n", arr[i], (i-1)/6 + 1, (i-1)%6 + 1);}/// 安排男生 (tmp 表示接下来要安置 学号为arr[tmp]的男生) for(int i = 6; i <= 30; i ++) {arr[i - 5] = i; }Permutation::MakeRndPermutation(arr, 25);for(int i = 1; i <= 5; i ++) {for(int j = 1; j <= 6; j ++) {if(store[i][j] == 0) { /// 发现空位 store[i][j] = arr[tmp ++]; /// 男生填空 }}}/// 生成好的排列储存在 store 中 for(int i = 1; i <= 5; i ++) {for(int j = 1; j <= 6; j ++) {posx[store[i][j]] = i;posy[store[i][j]] = j; /// 记录坐标信息 }}}void OutputToScreen() { /// 显示座位图 for(int i = 1; i <= 5; i ++) {for(int j = 1; j <= 6; j ++) {printf("%3d", store[i][j]);}puts("");}puts("");}bool CheckAdjoin(int i, int j) { /// 检测两人是否相邻 return abs(posx[i]-posx[j]) + abs(posy[i]-posy[j]) == 1;}
}

三、同学们最喜欢的概率计算问题

0.何谓 “相邻”

我们用posx(k)=xposx(k)=xposx(k)=x表示编号为k的同学在座位图中位于第x行。

我们用posy(k)=yposy(k)=yposy(k)=y表示编号为k的同学在作为图中位于第y列。

我们定义两个同学p、q相邻 ⇔∣posx(p)−posx(q)∣+∣posy(p)−posy(q)∣=1\Leftrightarrow|posx(p)-posx(q)|+|posy(p)-posy(q)|=1⇔∣posx(p)−posx(q)∣+∣posy(p)−posy(q)∣=1,即其中一个同学位于另一个同学的正前、正后、正左、正右四个方向上的相邻位置。

1.指定两个男生a和b,求他们相邻的概率

根据古典概型可知,ab两人相邻的概率为 ab两人相邻条件下的合法方案总数 除以总方案数Card(U)Card(U)Card(U)。

首先,ab两人的相对位置关系有如下相中可能出现的情况——左右相邻 or 前后相邻:

但是,实际情况中我们还需要考虑着两个同学的位置是否位于前三排。

假如这个图是班级的座位图:

那么,这两个人的座位可能有如下的几种情况:

上述五个图片分别代表了ab两人中“有两人位于前三排”、“有一人位于前三排”、“没有人位于前三排”这三种情况。

至此我们可以计算出ab两人相邻的概率(下文中我们用符号p′p'p′表示指定的两名男生处于相邻位置的概率):

p′=A22×(27×A165+6×A175+16×A185)×A2323Card(U)≈0.1136601307≈11.36%p'=\frac{A_2^2\times(27\times A_{16}^5+6\times A_{17}^5+16\times A_{18}^5)\times A_{23}^{23}}{Card(U)} \approx 0.1136601307 \approx 11.36\%p′=Card(U)A22​×(27×A165​+6×A175​+16×A185​)×A2323​​≈0.1136601307≈11.36%

理论计算的值与实际实验测得的概率惊人的相近,我进行了五次随机统计实验,每次统计实验中包含一千万次随机试验(注意区分实验试验——said csccsccsc),这五次试验测得的概率分别为:0.1135343,0.1136461,0.1135605,0.1135023,0.11375230.1135343, 0.1136461, 0.1135605, 0.1135023, 0.11375230.1135343,0.1136461,0.1135605,0.1135023,0.1137523,与理论值的相对误差不超过1%1\%1%。

2.指定三个男生 a,b,c ,要求a与b相邻,且a与c相邻,求概率

这个概率的计算过程相对复杂,我仍采用了上一个问题中的,枚举相对位置关系的方法,下图是我在学校徒手计算时的手稿:

由此可知题中所求概率(下文中我们用符号p′′p''p′′表示某一个指定男生与另两个指定的男生同时相邻的概率)为:

p′′=A22×(58×A155+16×A165+16×A175+28×A185)×A2222Card(U)≈0.0098609927≈1%p''=\frac{A_2^2\times(58\times A_{15}^5+16\times A_{16}^5+16\times A_{17}^5 + 28\times A_{18}^5)\times A_{22}^{22}}{Card(U)} \approx 0.0098609927 \approx 1\%p′′=Card(U)A22​×(58×A155​+16×A165​+16×A175​+28×A185​)×A2222​​≈0.0098609927≈1%

理论计算与实验结果又是惊人的相似,我又进行了五次实验,每次试验中包含一千万次随机试验,它们统计得到的概率分别为:0.0098445,0.0098264,0.0098552,0.0098357,0.00983270.0098445, 0.0098264, 0.0098552, 0.0098357, 0.00983270.0098445,0.0098264,0.0098552,0.0098357,0.0098327,与理论值的相对误差仍不超过1%1\%1%。

3.指定四个男生 a,b,c,d ,要求a与b相邻,且a与c相邻,且a与d相邻,求概率

有了前几个问题的经验,这一个问题解决起来就十分容易了。不再赘述,相关统计结果见手稿:

废话我都懒得写了,直接上公式:

p′′′=A33×(26×A145+14×A155+14×A175+8×A185)×A2121Card(U)≈0.0005749632≈0.057%p''' = \frac{A_3^3\times(26\times A_{14}^5 +14\times A_{15}^5+14\times A_{17}^5+8\times A_{18}^5)\times A_{21}^{21}}{Card(U)} \approx 0.0005749632 \approx 0.057 \%p′′′=Card(U)A33​×(26×A145​+14×A155​+14×A175​+8×A185​)×A2121​​≈0.0005749632≈0.057%

列举五次实验数据(每次试验包括一千万次试验):0.0005658,0.0005767,0.0005669,0.0005818,0.00056920.0005658, 0.0005767, 0.0005669, 0.0005818, 0.00056920.0005658,0.0005767,0.0005669,0.0005818,0.0005692。虽然说相对误差达到了2%2\%2%,但是由于这个事件发生的概率是在是太小了,所以从绝对误差角度看,这个准确程度是完全可以接受的。(相对误差2%2\%2%跟没有误差有冇区别…QwQ)

4.指定五个男生 a,b,c,d,e ,要求a与b相邻,且a与c相邻,且a与d相邻,且a与e相邻,求概率

显然,bcde这四个男生一定把男生a围在了中间,详见手稿。

可知:

p′′′′=A44×(4×A135+4×A145+4×A175)×A2020Card(U)≈0.0000166549≈0.0017%p'''' = \frac{A_4^4\times(4\times A_{13}^5+4\times A_{14}^5+4\times A_{17}^5)\times A_{20}^{20}}{Card(U)} \approx 0.0000166549 \approx 0.0017\%p′′′′=Card(U)A44​×(4×A135​+4×A145​+4×A175​)×A2020​​≈0.0000166549≈0.0017%

虽然我觉得这个时间发生的概率大概小到可以忽略不计了,这就意味着实验的统计值与理论值可能有较大的误差,但是我还是毅然决然地决定进行一千万次随机试验。。

实验过程中场面相当震撼:

一百八十万次试验竟然只检测到了34组满足要求的结果…

最后,实验统计结果为 0.00001810.00001810.0000181,虽然与理论值的误差达到了5%5\%5%以上,但考虑到绝对误差,理论预言几乎是完全准确的。

413\frac{1}{3}31​.指定六个男生 a,b,c,d,e,f,要求a与b,c,d,e,f 同时相邻,求概率

因为,与a同时相邻的最多只有4个,所以指定的五个同学不可能同时与a相邻,即概率为0。

423\frac{2}{3}32​.指定 k+1(k≥5)k+1 (k\geq 5)k+1(k≥5) 个男生 a,b1,b2,b3,...,bka,b_1,b_2,b_3,...,b_ka,b1​,b2​,b3​,...,bk​ 要求a与b1,b2,b3,...,bkb_1,b_2,b_3,...,b_kb1​,b2​,b3​,...,bk​同时相邻,求概率

因为,与a同时相邻的最多只有4个,所以指定的k(k≥5)k(k\geq 5)k(k≥5)个同学不可能同时与a相邻,即概率为0。

5.指定两个男生a和b,求他们不相邻的概率

我们接下来用符号P0(1)P_0(1)P0​(1)来表示这个值,由于a和b要么相邻,要么不相邻,所以:

P0(1)=1−p′≈0.8863398693≈88.6%P_0(1)=1-p'\approx 0.8863398693 \approx 88.6\%P0​(1)=1−p′≈0.8863398693≈88.6%

6.指定三个男生a,b,c,已知a与b不相邻,且a与c也不相邻,求概率

下文中我们用符号P0(2)P_0(2)P0​(2)表示这个值,简单的容斥原理就可以一步搞定。

记事件M表示a与b相邻,事件N表示a与c相邻,如下图韦恩图所示:

P0(2)=P(∁U(M∪N))=1−P(M)−P(N)+P(M∩N)=1−2p′+p′′≈0.7825407313≈78.3%P_0(2)=P(\complement_U (M\cup N))=1-P(M)-P(N)+P(M\cap N)=1-2p'+p''\approx 0.7825407313 \approx 78.3\%P0​(2)=P(∁U​(M∪N))=1−P(M)−P(N)+P(M∩N)=1−2p′+p′′≈0.7825407313≈78.3%

7.指定k+1(k≥4)k+1(k\geq 4)k+1(k≥4)个男生 a,b1,b2,b3,...,bka,b_1,b_2,b_3,...,b_ka,b1​,b2​,b3​,...,bk​ 要求a与b1,b2,b3,...,bkb_1,b_2,b_3,...,b_kb1​,b2​,b3​,...,bk​中任何一人都不相邻,

下文中我们用符号P0(k)P_0(k)P0​(k)表示这个值,仍然可以根据容斥原理表示出运算结果。

P0(k)=Ck0−Ck1p′+Ck2p′′−Ck3p′′′+Ck4p′′′′−...P_0(k)=C_k^0-C_k^1p'+C_k^2p''-C_k^3p'''+C_k^4p''''-...P0​(k)=Ck0​−Ck1​p′+Ck2​p′′−Ck3​p′′′+Ck4​p′′′′−...

但是,根据问题4234\frac{2}{3}432​中的结论,上式中“…”所代表的的项实际上都是零,所以:

P0(k)=Ck0−Ck1p′+Ck2p′′−Ck3p′′′+Ck4p′′′′P_0(k)=C_k^0-C_k^1p'+C_k^2p''-C_k^3p'''+C_k^4p''''P0​(k)=Ck0​−Ck1​p′+Ck2​p′′−Ck3​p′′′+Ck4​p′′′′

8.假说演绎法:通过两种方法计算P0(24)P_0(24)P0​(24)的值,从而验证问题7中结论的正确性。

方法1:带入问题7结论:

P0(24)=C240−C241p′+C242p′′−C243p′′′+C244p′′′′≈0.0070401494P_0(24)=C_{24}^0-C_{24}^1p'+C_{24}^2p''-C_{24}^3p'''+C_{24}^4p'''' \approx 0.0070401494P0​(24)=C240​−C241​p′+C242​p′′−C243​p′′′+C244​p′′′′≈0.0070401494

方法2:由于班级中一共有25名男生,所以说P0(24)P_0(24)P0​(24)意味着男生a,不能与任何男生相邻,而只能与女生相邻。用分类加法计数原理统计男生a被女生团团围住的方案即可,给出手稿:

得到公式为:

P0(24)=(2×A52×A153+4×A53×A142+4×A54×A131)×A2424Card(U)≈0.0061904762P_0(24)=\frac{(2\times A_5^2\times A_{15}^3+4\times A_5^3\times A_{14}^2+4\times A_5^4\times A_{13}^1)\times A_{24}^{24}}{Card(U)} \approx 0.0061904762P0​(24)=Card(U)(2×A52​×A153​+4×A53​×A142​+4×A54​×A131​)×A2424​​≈0.0061904762

然后我们惊奇地发现两个结果竟然不一样?!!谁出错了!!?(这时我的内心是崩溃的,可能又要靠实验来说话了!)

一千万次随机试验得到的概率为0.00703540.00703540.0070354,我的天,问题7得到的结论竟然是对的!竟然比我们后来又提出来的这个算法还要精确得多!Why?

哦!我知道了,后来提出的这种算法少考虑了两种情况!!即a同学在第二行最左侧位置和最右侧位置的情况!!加上之后再看看??

P0(24)=(2×A52×A153+4×A53×A142+4×A54×A131+2×A53×A142)×A2424Card(U)≈0.0070401494P_0(24)=\frac{(2\times A_5^2\times A_{15}^3+4\times A_5^3\times A_{14}^2+4\times A_5^4\times A_{13}^1+2\times A_5^3\times A_{14}^2)\times A_{24}^{24}}{Card(U)} \approx 0.0070401494P0​(24)=Card(U)(2×A52​×A153​+4×A53​×A142​+4×A54​×A131​+2×A53​×A142​)×A2424​​≈0.0070401494

我的天,竟然与理论值完全相同(精确到小数点后10位的条件下)!!

不妨把小数点移动至小数点后更多的位数:

0.12345678901234567890123456789012345678 (帮助你数位数用的一行数字)
0.00704014939309056939401552932533689955 (方法1)
0.00704014939309056956172805288168836668 (方法2)

说实话我是用C++中的long double计算的,我觉得这个精度足够了。计算得到的这两个数在小数点后的前18位都是相同的,说明它们应该是有着相同的组合意义。

四、同学们徒手就可以计算出的一些简单概率问题

1.男生a坐在前三排某一指定位置的概率

P1=A175×A2424Card(U)=269≈0.0288888889≈2.89%P_1 = \frac{A_{17}^{5}\times A_{24}^{24}}{Card(U)} =\frac{26}{9} \approx 0.0288888889 \approx 2.89\%P1​=Card(U)A175​×A2424​​=926​≈0.0288888889≈2.89%

试验数据为:0.0289321≈2.89%0.0289321\approx 2.89\%0.0289321≈2.89%,误差在合理范围内。

男生a坐在两个不同位置上从而形成的两个事件为互斥事件。由此可知,男生坐在前三排的概率为(请注意这里不是约等于):

18P=52%18P = 52\%18P=52%

我们不妨用实验去验证一下这个计算结果:0.5202649≈52%0.5202649\approx 52\%0.5202649≈52%,在合理误差范围内。

2.女生a坐在前三排某一指定位置的概率

P2=A174×A2525Card(U)=118≈5.56%P_2 = \frac{A_{17}^4\times A_{25}^{25}}{Card(U)}=\frac{1}{18}\approx 5.56\%P2​=Card(U)A174​×A2525​​=181​≈5.56%

3.男生a与女生b相邻的概率

与两男相邻有很大的相似之处,只是由于女生只能坐在前三排,所以就去掉了两人位置都在后两排的情况。

P3=27×A22×A164+6×A174Card(U)≈0.1050980392≈10.5%P_3 = \frac{27\times A_2^2\times A_{16}^4+6\times A_{17}^4}{Card(U)} \approx0.1050980392\approx10.5\%P3​=Card(U)27×A22​×A164​+6×A174​​≈0.1050980392≈10.5%

五、受影响下的实践概率

0.0280540   0.0285191   0.0284975   0.0284215   0.0285086   0.0281117
0.0284118   0.0291249   0.0289828   0.0290540   0.0290901   0.0284643
0.0286462   0.0292079   0.0292290   0.0293314   0.0293300   0.0286686
0.0396448   0.0413433   0.0412379   0.0411593   0.0413348   0.0397338
0.0390136   0.0400485   0.0399276   0.0399483   0.0399662   0.0389885

附录、“验证程序”的完整实现

#include <cstdio>
#include <cstdlib>
#include <ctime>
#include <cmath>
#include <cstring>
#include <queue>
#include <algorithm>
using namespace std;//#define double long double/// 2019.5.31 主题: NEYC 1702 排座 问题模型
/// 命名规则: 变量名、字段名等首字母小写, 函数名、类名等首字母大写 int RND() { /// 利用c语言自带的随机数生成器 return rand()*32768 + rand();
}namespace Permutation { /// 用于生成随机排列 struct Pair {int val, rght; /// val 实际值, rght 权值 } ns[30 + 3];bool Cmp(const Pair& p1, const Pair& p2) { /// 用于随机排列 return p1.rght < p2.rght; /// 按照权值升序排列 }void MakeRndPermutation(int* arr, int n) { /// 构造随机排列 memset(ns, 0x00, sizeof(ns));for(int i = 1; i <= n; i ++) {ns[i] = (Pair){arr[i], RND()}; /// 载入数据 }sort(ns+1, ns+n+1, Cmp); /// 随机排列 for(int i = 1; i <= n; i ++) {arr[i] = ns[i].val; /// 存回数据 }}
}namespace Graph { /// 生成座位图 /// 学号 1~30, 其中 1~5 为女生, 6~30 为男生/// 女生必须坐在前三排 int store[7][7]; /// 6 * 6 的座位图 int posx[30 + 3], posy[30 + 3]; /// 每个同学的位置 void Construct() { /// 构造一个座位图 int arr[30 + 3] = {}, tmp = 1;memset(store, 0x00, sizeof(store)); /// 注意数据清零 /// posx posy 理论上会被完全覆盖, 再次不再清零 /// 安排女生 for(int i = 1; i <= 5; i ++) {arr[i] = i;}Permutation::MakeRndPermutation(arr, 18); /// 随机排列 for(int i = 1; i <= 18; i ++) {store[(i-1)/6 + 1][(i-1)%6 + 1] = arr[i];//printf("set %d at %d, %d\n", arr[i], (i-1)/6 + 1, (i-1)%6 + 1);}/// 安排男生 (tmp 表示接下来要安置 学号为arr[tmp]的男生) for(int i = 6; i <= 30; i ++) {arr[i - 5] = i; }Permutation::MakeRndPermutation(arr, 25);for(int i = 1; i <= 5; i ++) {for(int j = 1; j <= 6; j ++) {if(store[i][j] == 0) { /// 发现空位 store[i][j] = arr[tmp ++]; /// 男生填空 }}}/// 生成好的排列储存在 store 中 for(int i = 1; i <= 5; i ++) {for(int j = 1; j <= 6; j ++) {posx[store[i][j]] = i;posy[store[i][j]] = j; /// 记录坐标信息 }}}void OutputToScreen() { /// 显示座位图 for(int i = 1; i <= 5; i ++) {for(int j = 1; j <= 6; j ++) {printf("%3d", store[i][j]);}puts("");}puts("");}bool CheckAdjoin(int i, int j) { /// 检测两人是否相邻 return abs(posx[i]-posx[j]) + abs(posy[i]-posy[j]) == 1;}bool CheckNotDivide(int i) { /// 检测同学 i周围是否有男生 int x = posx[i], y = posy[i];return store[x-1][y]>5 || store[x][y-1]>5 || store[x+1][y]>5 || store[x][y+1]>5;/// 由于边界之外的位置都是0 所以不需要特殊判断 }
}namespace Tests { /// 一些随机试验 void MaleFemaleAdjoinRate() { /// 探究一男一女相邻的概率 int cnt = 0; /// 统计 10号和 1号相邻次数 int t; /// 实验次数 printf("请输入实验次数: "); scanf("%d", &t); for(int i = 1; i <= t; i ++) {Graph::Construct();if(Graph::CheckAdjoin(10, 1)) {cnt ++;}if(i % 100000 == 0) {printf("已完成 %10d / %10d 次试验, 检测到相邻次数为: %10d \n", i, t, cnt);}}printf("实验结束, 指定两男相邻的概率为: %.10lf\n", (double)cnt/t);}void TwoMaleAdjoinRate() { /// 探究两男相邻的概率 int cnt = 0; /// 统计 10号和 13号相邻次数 int t; /// 实验次数 printf("请输入实验次数: "); scanf("%d", &t); for(int i = 1; i <= t; i ++) {Graph::Construct();if(Graph::CheckAdjoin(10, 13)) {cnt ++;}if(i % 100000 == 0) {printf("已完成 %10d / %10d 次试验, 检测到相邻次数为: %10d \n", i, t, cnt);}}printf("实验结束, 指定两男相邻的概率为: %.10lf\n", (double)cnt/t);}void ThreeMaleAdjoinRate() { /// 探究三男相邻的概率 int cnt = 0; /// 统计 10号和 13号相邻 且 10号与 23号相邻 次数 int t; /// 实验次数 printf("请输入实验次数: "); scanf("%d", &t); for(int i = 1; i <= t; i ++) {Graph::Construct();if(Graph::CheckAdjoin(10, 13) && Graph::CheckAdjoin(10, 23)) {cnt ++;}if(i % 100000 == 0) {printf("已完成 %10d / %10d 次试验, 检测到相邻次数为: %10d \n", i, t, cnt);}}printf("实验结束, 指定两男相邻的概率为: %.10lf\n", (double)cnt/t);}void FourMaleAdjoinRate() { /// 探究四男相邻的概率 int cnt = 0; /// 统计 10号和 13号相邻 且 10号与 23号相邻 且 10号与 25号相邻 次数 int t; /// 实验次数 printf("请输入实验次数: "); scanf("%d", &t); for(int i = 1; i <= t; i ++) {Graph::Construct();if(Graph::CheckAdjoin(10, 13) && Graph::CheckAdjoin(10, 23) && Graph::CheckAdjoin(10, 25)) {cnt ++;}if(i % 100000 == 0) {printf("已完成 %10d / %10d 次试验, 检测到相邻次数为: %10d \n", i, t, cnt);}}printf("实验结束, 指定两男相邻的概率为: %.10lf\n", (double)cnt/t);}void FiveMaleAdjoinRate() { /// 探究五男相邻的概率 int cnt = 0;int t; /// 实验次数 printf("请输入实验次数: "); scanf("%d", &t); for(int i = 1; i <= t; i ++) {Graph::Construct();if(Graph::CheckAdjoin(10, 13) && Graph::CheckAdjoin(10, 23) && Graph::CheckAdjoin(10, 25) && Graph::CheckAdjoin(10, 9)) {cnt ++;}if(i % 100000 == 0) {printf("已完成 %10d / %10d 次试验, 检测到相邻次数为: %10d \n", i, t, cnt);}}printf("实验结束, 指定两男相邻的概率为: %.10lf\n", (double)cnt/t);}void MaleDivideRate() { /// 探究P_0(24)的概率 int cnt = 0;int t; /// 实验次数 printf("请输入实验次数: "); scanf("%d", &t); for(int i = 1; i <= t; i ++) {Graph::Construct();if(!Graph::CheckNotDivide(10)) {cnt ++;}if(i % 100000 == 0) {printf("已完成 %10d / %10d 次试验, 检测到相邻次数为: %10d \n", i, t, cnt);}}printf("实验结束, 指定两男相邻的概率为: %.10lf\n", (double)cnt/t);}
}namespace Calculation { /// 排列数计算 double fac[30 + 3]; /// 计算阶乘 void Init() { /// 初始化数学功能 fac[0] = 1;for(int i = 1; i <= 30; i ++) {fac[i] = fac[i-1] * i;}}inline double Fact(int x) { /// 计算阶乘 return fac[x];}inline double A(int n, int m) { /// 计算组合数 return Fact(n)/Fact(n-m);}inline double C(int n, int m) {return Fact(n)/(Fact(n-m)*Fact(m));}
}
//#define Cal Calculation
using namespace Calculation;int main() {Calculation::Init(); /// 初始化数学功能 srand(time(NULL));   /// 重置随机种子 double p1 = A(2, 2)*(27*A(16, 5)+6*A(17, 5)+16*A(18, 5))*A(23, 23)/(A(18, 5)*A(25, 25));double p2 = A(2, 2)*(58*A(15, 5)+16*A(16, 5)+16*A(17, 5)+28*A(18, 5))*A(22, 22)/(A(18, 5)*A(25, 25));//Tests::ThreeMaleAdjoinRate();double p3 = A(3, 3)*(26*A(14, 5)+14*A(15, 5)+14*A(17, 5)+8*A(18, 5))*A(21, 21)/(A(18, 5)*A(25, 25));//Tests::FiveMaleAdjoinRate();double p4 = A(4, 4)*(4*A(13, 5)+4*A(14, 5)+4*A(17, 5))*A(20, 20)/(A(18, 5)*A(25, 25));double p0_24_1 = 1-C(24, 1)*p1+C(24, 2)*p2-C(24, 3)*p3+C(24, 4)*p4;double p0_24_2 = (2*A(5, 2)*A(15, 3)+6*A(5, 3)*A(14, 2)+4*A(5, 4)*A(13, 1))*A(24, 24)/(A(18, 5)*A(25, 25));//printf("%.38lf\n%.38lf\n", p0_24_1, p0_24_2);//Tests::MaleDivideRate();system("pause");return 0;
}

NEYC 1702 排座 问题模型相关推荐

  1. 基于JSP的高校考试排座管理系统

    目 录 摘 要 i Abstract ii 第1章 绪 论 1 1.1本文工作的来源 1 1.2目的和意义 2 1.2.1 目的 2 1.2.2意义 2 1.3国内外进展 3 1.3.1国外进展 3 ...

  2. 九九乘法表代码口述_利用随机函数实现座次表的随机排座

    昨天听完讲座,晚上忍不住写了份学后感,今天有老师在文章下留言问如何实现随机排座,上午在快速理赔中心处理交通事故,处理完后将车开去4S店维修,回来后给娃做完中饭就开始写代码实现这个功能,因为有C++功底 ...

  3. c语言程序设计考场排座位,“听说学霸座位是这个?”老师揭秘排座,真正的C位其实在这里……...

    来源:小学数学(ID:xxsx100) 新学期,每个班级都要排座位. 关于教室中所谓"抢C位",每年都是不少家长心里相当关切的事儿,尤其在新学期开始,常有家长悄悄找到老师,或直接或 ...

  4. 会议OA项目(我的会议中的会议排座送审功能)

    文章目录 一.会议排座插件介绍 1)会议项目为什么要有会议排座的功能 2)完成在页面上元素的拖动功能 2.1分析现有素材的不足 2.2修改现有素材的不足⬇⬇⬇ 2.3 content需要传递到后台,并 ...

  5. OA之我的会议(会议排座送审)

    目录 一.会议排座插件介绍 需求背景: 1.实现思路: 2.明确了开发会议排座的意义 1.查询出本场会议中的所有参与人员2.需要完成在页面上元素的拖动功能,把对应的参会人员放在指定位置,如:重要的人就 ...

  6. 会议OA(会议排座送审)

    目录 一,会议排座 二,会议送审 一,会议排座 分析: 1. 查找资料     做选择,哪一个素材更适合完成需求 2. 素材改造     素材的缺陷:         ①:样式:座位小方块重叠/太小 ...

  7. OA之会议排座与送审

    目录 一.会议排座 二.送审 一.会议排座 1.会议排座插件 为了实现会议排座功能,我们需要再网上寻找一个会议排座的插件.可以上百度搜索 在网上找到的一个插件,但是发现了以下两个问题: ①.发现元素重 ...

  8. 会议OA之会议排座送审

    目录 最近这段时间一直都在与大家分享会议OA项目,今天继续分享关于会议OA项目的一个亮点功能,会议排座.以及一个送审功能. 一.会议排座 二.送审 最近这段时间一直都在与大家分享会议OA项目,今天继续 ...

  9. 列车排座2 算法笔试题

    文章目录 题目 分析 代码实现 题目 列车排座2 题目描述: 有n位乘客乘坐一列列车,列车一共会依次经过105个站点,从1到105编号. 我们已知每一位乘客的上车站点和下车站点,但是不知道这些乘客的订 ...

最新文章

  1. vim 有用命令-20190217
  2. linux 内核 3.18,Linux Kernel 3.18 正式版发布下载
  3. boost::qvm::deduce_quat相关的测试程序
  4. python xlwt写入已有表_Python中,添加写入数据到已经存在的Excel文件
  5. python调用jenkinsAPI构建jenkins,并传递参数
  6. 自定义QListWidget实现item被hover时改变图标样式(模仿网易云音乐选项列表)(方法二)
  7. 让你的网站首页自动选择语言转跳
  8. 最新!全球学术排名出炉:21 所中国大学位居世界 100 强
  9. TSP-遗传算法求解
  10. Qt echarts 教程(3):qml echarts 的使用方法
  11. dwg转换pdf方法
  12. spss多元线性回归散点图_利用SPSS进行线性回归分析
  13. 计算机网络总线型结构优,总线型拓扑结构优缺点是什么
  14. 苹果开发证书导出P12的问题
  15. 二项式系数表--杨辉三角形
  16. 拼多多收php吗_拼多多果园助力PHP版可运行在云函数
  17. 2020年每个Web开发人员必须知道的9种Web技术
  18. 堆优化版迪杰斯特拉(Dijkstra)算法简单分析
  19. 让你能进“大厂”的数据分析项目是长怎样?全套路线(建议收藏)
  20. pta 7-29 螺旋矩阵

热门文章

  1. 解决QQ群文件未通过安全检测无法下载问题
  2. axurerp出现错误报告_安装好axure8.1以后,打开直接报错退出
  3. 双击 文字 出现 文本框 的方法
  4. 如何在浏览器中打开jupyter notebook
  5. linux硬件命令大全,Linux硬件信息命令大全
  6. 时间格式转换,转时间戳,转UTC,转中国标准时间
  7. 404常见的几种错误原因
  8. 软考--后缀式(逆波兰式)的两种求法
  9. k8s集群搭建(亲测有效)
  10. watch监听和computed计算属性的使用和区别