一个有趣的题目

有100个囚犯,监狱长想玩一个囚徒释放的游戏,在一个封闭的房间里放着一排张卡片,卡片反面都一样,正面写了每个人的名字,总共100张。

囚犯依次进入房间,每人最多翻50张卡片。如果翻开的卡片号码与自己的名字一致,那么这个囚犯就成功了。当且仅当所有的囚犯成功,大家才能被释放。

为了能够成功逃脱,囚犯们在玩游戏之前可以一起商量选卡片的策略?


注意:

1.囚犯依次进房间,进房间时以及进房间前后,都不能互相交流,包括什么暗示什么的都不能。

2.不能做任何记号,不允许把卡片拿出来或互换位置,哪怕是自己的号码。

3.每个囚犯进房间的时候,房间的布置是一模一样的。

 
 
 结论:概率约为 0.31183 。(推广到人数为n ,概率不低于 0.3 )
 策略:置换群+不相交循环。
 该题目改编自:100 prisoners problem   思路为:https://www.zhihu.com/question/27050108
 
囚徒们提前商量编号,问题就转换了。以6个抽屉为例:
6个抽屉里的号码随机排序有6!=720种
能够正确的排序种类有如下几种情况:
1、所有6个号码对位(只有123456)=============1种情况
2、其中任意4个号码对位,另2个互换位置(比如123465)==C(6,4)=15种情况
3、其中任意3个号码对位,另3个互换位置(比如123564)==C(6,3)*2=40种情况
4、其中任意2个号码对位,另4个两两互换位置(比如124365)==C(6,2)*C(4,2)/2=45种情况
5、其中任意1个号码对位,另外任意两个互换位置,其余三个互换位置(比如132564)==C(6,1)*C(5,2)*2=120种情况
6、没有号码对位,分成两组,每组3个号码互换位置(比如231564)==C(6,3)/A(2,2)*2*2=40种情况
7、没有号码对位,分成三组,每组2个号码互换位置(比如214365)==C(6,2)*C(4,2)/A(3,3)=15种情况
共计:1+15+40+45+120+40+15=276种
成功的概率为276/720=23/60
 
因此100个也就是
情况1、循环长度为51数:A(100,49)*50!=100!/51!*50!=100!/51
情况2、循环长度为52数:A(100,48)*51!=100!/52!*51!=100!/52
情况3、循环长度为53数:100!/53
.......
情况50、循环长度为100数:100!/100
共计100!/51+100!/52+100!/53+.......+100!/100
即100!-(100!/51+100!/52+100!/53+.......+100!/100)能完成。
概率为1-1/51-1/52-1/53-......-1/100=0.311827821
 
amazing!!! (例子源于: 真正傲雪冰寒
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

转载于:https://www.cnblogs.com/ISGuXing/p/9807133.html

### 有趣的跳跃问题概述 在C语言编程中,“有趣的跳跃”(Jolly Jumping)是一个经典的编程问题。该问题要求判断一个整数序列是否满足“跳跃序列”的条件。具体来说,给定一个长度为 $ n $ 的整数序列 $ a_1, a_2, \dots, a_n $,其相邻元素之间的绝对差值的集合必须包含从 $ 1 $ 到 $ n-1 $ 的所有整数,并且不能有重复的差值。 例如,序列 `1 4 2 3` 是一个 Jolly 跳跃序列,因为其相邻差值分别为 `3`, `2`, `1`,涵盖了从 $ 1 $ 到 $ 3 $ 的所有整数[^1]。 ### 编程题目描述 **题目:** 编写一个程序,输入一个整数序列,判断它是否是“Jolly 跳跃”序列。如果是,则输出 `Jolly`,否则输出 `Not jolly`。 **输入格式:** 第一行输入一个整数 $ n $ 表示序列的长度,随后输入 $ n $ 个整数。 **输出格式:** 输出 `Jolly` 或 `Not jolly`。 ### 示例代码解析 以下是一个完整的 C 语言实现: ```c #include <stdio.h> #include <math.h> #include <string.h> int main() { int n, i, o = 0; int a[1000], b[1000]; scanf("%d", &n); if (n == 1) { printf("Jolly"); return 0; } for (i = 0; i < n; i++) { scanf("%d", &a[i]); } for (i = 0; i < n - 1; i++) { b[i] = abs(a[i] - a[i + 1]); } int flag[1000] = {0}; for (i = 0; i < n - 1; i++) { if (b[i] >= 1 && b[i] <= n - 1) { flag[b[i]]++; } else { break; } } for (i = 1; i <= n - 1; i++) { if (flag[i] != 1) { printf("Not jolly"); return 0; } } printf("Jolly"); return 0; } ``` #### 代码说明: 1. **输入处理:** - 首先读取序列长度 $ n $。 - 然后读取 $ n $ 个整数并存储到数组 `a` 中。 2. **计算相邻差值:** - 使用 `abs()` 函数计算相邻元素的绝对差值,并将结果存储在数组 `b` 中。 3. **验证差值范围与唯一性:** - 创建一个标记数组 `flag`,用于记录每个差值出现的次数。 - 如果某个差值超出 $ [1, n-1] $ 范围,则直接判定为非 Jolly 序列。 - 检查每个差值是否恰好出现一次。 4. **输出结果:** - 如果所有差值都满足条件,则输出 `Jolly`;否则输出 `Not jolly`。 ### 测试用例 | 输入 | 输出 | |------|------| | `6 11 15 14 13 12 10` | `Jolly` | | `4 1 2 4 7` | `Not jolly` | | `1 100` | `Jolly` | ### 总结 “有趣的跳跃”问题不仅考察了对数组、循环和条件判断的掌握,还涉及对数据唯一性和范围的检查。上述代码通过合理使用数组和逻辑判断,能够高效地解决此类问题
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值