[原创]10个人都不坐在自己座位上有多少种可能机率多大
来源:互联网 发布:seo网络营销是什么 编辑:程序博客网 时间:2024/05/06 00:39
从郑州出差回来,在高铁上,项目经理突然问我这个问题,我们讨论了很久,试了各种方法,也没有得出一个能够通用的计算结果的公式,但是却先答道了答案。
想我堂堂程序员,比不过数学家,但是写个程序求结果还是非常非常容易的。
下面一起来看验证结果的过程。
直接贴代码。
答案是 当人数趋向于无穷大时,结果是 自然数E的倒数 = 1/e
以下是java程序验证。
package com.weiwo.seat;import java.util.ArrayList;import java.util.List;/** * 如果一辆车上有10个人(不包括司机和售票员),10个座位,中途休息时10个人都下车了,休息结束时,10个人回到车上。请问, * 这10个人都不坐在自己座位上有多少种可能(或者求机有多大)?经理说答案是 自然数E的倒数 = 1/e * * @author peaches * @date 2015-2-6下午10:57:21 */public class Seat {public static void main(String[] args) {for (int i = 1; i < 11; i++) {Seat seat = new Seat();seat.peopleNum = i;seat.execute();}}private int num = 1;public int peopleNum = 5;private List<String> peopleList = new ArrayList<String>();// 人private List<String> seatList = new ArrayList<String>();// 座位,每个座位默认对应一个人private List<List<String>> newPeopleSeatList = new ArrayList<List<String>>();// 排列组合结果public void execute() {for (int i = 1; i < peopleNum + 1; i++) {String people = String.valueOf(i);peopleList.add(people);seatList.add(people);}// System.out.println(Arrays.toString(peopleList.toArray()));// System.out.println(Arrays.toString(seatList.toArray()));generateList(0);valid();}/** * 验证排列组合,只保留所有的都不在原来座位上的。删除任何存在“在自己座位上的排列组合” */private void valid() {int count = newPeopleSeatList.size();// 所有排列总数System.out.println("总人数:" + peopleList.size());for (int i = 0; i < newPeopleSeatList.size(); i++) {List<String> tempList = newPeopleSeatList.get(i);if (!validList(tempList)) {newPeopleSeatList.remove(i);i--;}}// System.out.println(num++ + ":" +// Arrays.toString(newPeopleSeatList.toArray()));System.out.println("所有人均不在自己座位上的可能数量:" + newPeopleSeatList.size());System.out.println("所有人均不在自己座位上的可能机率:" + String.format("%.3f%%", newPeopleSeatList.size() * 1.0 / count * 100));System.out.println("----------------------------------------------------------------");}private boolean validList(List newList) {for (int i = 0; i < seatList.size(); i++) {if (newList.get(i).equals(seatList.get(i))) {return false;}}return true;}/** * 生成所有的可能的组合 * * 程序的主要思路是: 1.把第1个数换到最前面来(本来就在最前面),准备打印1xx,再对后两个数2和3做全排列。 * 2.把第2个数换到最前面来,准备打印2xx,再对后两个数1和3做全排列。 3.把第3个数换到最前面来,准备打印3xx,再对后两个数1和2做全排列。 * * 可见这是一个递归的过程,把对整个序列做全排列的问题归结为对它的子序列做全排列的问题,注意我没有描述Base Case怎么处理,你需要自己想。 * 你的程序要具有通用性,如果改变了N和数组a的定义(比如改成4个数的数组),其它代码不需要修改就可以做4个数的全排列(共24种排列)。 * * 完成了上述要求之后再考虑第二个问题:如果再定义一个常量M表示从N个数中取几个数做排列(N==M时表示全排列),原来的程序应该怎么改? * * 最后再考虑第三个问题:如果要求从N个数中取M个数做组合而不是做排列,就不能用原来的递归过程了,想想组合的递归过程应该怎么描述,编程实现它。 */public void generateList(int k) {if (k == peopleNum) {List<String> tempList = new ArrayList<String>();tempList.addAll(peopleList);newPeopleSeatList.add(tempList);// System.out.println(num++ + ":" +// Arrays.toString(newPeopleSeatList.toArray()));} else {for (int i = k; i < peopleNum; ++i) {swap(i, k);// 交换前缀generateList(k + 1);// 递归swap(i, k);// 将前缀换回来,继续做前一次排列}}}public void swap(int i, int offset) {String tempI = peopleList.get(i);String tempOffset = peopleList.get(offset);peopleList.remove(i);peopleList.add(i, tempOffset);peopleList.remove(offset);peopleList.add(offset, tempI);}}
最终计算结果是
总人数:1
所有人均不在自己座位上的可能数量:0
所有人均不在自己座位上的可能机率:0.000%
----------------------------------------------------------------
总人数:2
所有人均不在自己座位上的可能数量:1
所有人均不在自己座位上的可能机率:50.000%
----------------------------------------------------------------
总人数:3
所有人均不在自己座位上的可能数量:2
所有人均不在自己座位上的可能机率:33.333%
----------------------------------------------------------------
总人数:4
所有人均不在自己座位上的可能数量:9
所有人均不在自己座位上的可能机率:37.500%
----------------------------------------------------------------
总人数:5
所有人均不在自己座位上的可能数量:44
所有人均不在自己座位上的可能机率:36.667%
----------------------------------------------------------------
总人数:6
所有人均不在自己座位上的可能数量:265
所有人均不在自己座位上的可能机率:36.806%
----------------------------------------------------------------
总人数:7
所有人均不在自己座位上的可能数量:1854
所有人均不在自己座位上的可能机率:36.786%
----------------------------------------------------------------
总人数:8
所有人均不在自己座位上的可能数量:14833
所有人均不在自己座位上的可能机率:36.788%
----------------------------------------------------------------
总人数:9
所有人均不在自己座位上的可能数量:133496
所有人均不在自己座位上的可能机率:36.788%
----------------------------------------------------------------
总人数:10
人数10一直没有算出来,10!=3628800
我写的这个只是用于验证,并没有做优化,算法的时间和空间复杂度比较高,10! 会非常耗时,大约执行了30你分钟也没有执行出来结果……
有觉得有兴趣的朋友可以优化下。
----------------------------------------------------------------------------------------------------------------------------------------------
2015-02-11
优化后的代码
优化后的代码,可以算出10个人的时候的几率,这也只能算出来10个人,11个就内存溢出了,可能是我设置的不够大,但是也说明这不是一个很好的算法。
[code=java]package com.Test;
import java.util.ArrayList;
import java.util.List;
/**
* 如果一辆车上有10个人(不包括司机和售票员),10个座位,中途休息时10个人都下车了,休息结束时,10个人回到车上。请问, 这10个人都不坐在自己座位上有多少种可能(或者求机有多大)?经理说答案是 自然数E的倒数 = 1/e
*
* @author peaches
* @date 2015-2-6下午10:57:21
*/
public class TestSeat {
public static void main(String[] args) {
for (int i = 0; i < 11; i++) {
long startTime = System.currentTimeMillis();
TestSeat seat = new TestSeat();
seat.peopleNum = i;
seat.execute();
System.out.println("执行时间" + (System.currentTimeMillis() - startTime));
}
}
private final int num = 1;
public int peopleNum = 5;
private final List<String> peopleList = new ArrayList<String>();// 人
private final List<String> seatList = new ArrayList<String>();// 座位,每个座位默认对应一个人
private final List<List<String>> newPeopleSeatList = new ArrayList<List<String>>();// 排列组合结果
public void execute() {
for (int i = 1; i < peopleNum + 1; i++) {
String people = String.valueOf(i);
peopleList.add(people);
seatList.add(people);
}
// System.out.println(Arrays.toString(peopleList.toArray()));
// System.out.println(Arrays.toString(seatList.toArray()));
generateList(0);
valid();
}
/**
* 验证排列组合,只保留所有的都不在原来座位上的。删除任何存在“在自己座位上的排列组合”
*/
private void valid() {
List<List<String>> resultPeopleSeatList = new ArrayList<List<String>>();// 排列组合结果
int count = newPeopleSeatList.size();// 所有排列总数
System.out.println("总人数:" + peopleList.size());
for (int i = newPeopleSeatList.size() - 1; i > 0; i--) {
List<String> tempList = newPeopleSeatList.get(i);
if (validList(tempList)) {
resultPeopleSeatList.add(newPeopleSeatList.get(i));
}
newPeopleSeatList.remove(i);
}
// System.out.println(num++ + ":" +
// Arrays.toString(newPeopleSeatList.toArray()));
System.out.println("所有人均不在自己座位上的可能数量:" + resultPeopleSeatList.size());
System.out.println("所有人均不在自己座位上的可能机率:" + String.format("%.3f%%", resultPeopleSeatList.size() * 1.0 / count * 100));
System.out.println("----------------------------------------------------------------");
}
private boolean validList(List newList) {
for (int i = 0; i < seatList.size(); i++) {
if (newList.get(i).equals(seatList.get(i))) {
return false;
}
}
return true;
}
/**
* 生成所有的可能的组合
*
* 程序的主要思路是: 1.把第1个数换到最前面来(本来就在最前面),准备打印1xx,再对后两个数2和3做全排列。 2.把第2个数换到最前面来,准备打印2xx,再对后两个数1和3做全排列。 3.把第3个数换到最前面来,准备打印3xx,再对后两个数1和2做全排列。
*
* 可见这是一个递归的过程,把对整个序列做全排列的问题归结为对它的子序列做全排列的问题,注意我没有描述Base Case怎么处理,你需要自己想。 你的程序要具有通用性,如果改变了N和数组a的定义(比如改成4个数的数组),其它代码不需要修改就可以做4个数的全排列(共24种排列)。
*
* 完成了上述要求之后再考虑第二个问题:如果再定义一个常量M表示从N个数中取几个数做排列(N==M时表示全排列),原来的程序应该怎么改?
*
* 最后再考虑第三个问题:如果要求从N个数中取M个数做组合而不是做排列,就不能用原来的递归过程了,想想组合的递归过程应该怎么描述,编程实现它。
*/
public void generateList(int k) {
if (k == peopleNum) {
List<String> tempList = new ArrayList<String>();
tempList.addAll(peopleList);
newPeopleSeatList.add(tempList);
// System.out.println(num++ + ":" +
// Arrays.toString(newPeopleSeatList.toArray()));
} else {
for (int i = k; i < peopleNum; ++i) {
swap(i, k);// 交换前缀
generateList(k + 1);// 递归
swap(i, k);// 将前缀换回来,继续做前一次排列
}
}
}
public void swap(int i, int offset) {
String tempI = peopleList.get(i);
String tempOffset = peopleList.get(offset);
peopleList.remove(i);
peopleList.add(i, tempOffset);
peopleList.remove(offset);
peopleList.add(offset, tempI);
}
}[/code]
执行结果
总人数:0
所有人均不在自己座位上的可能数量:0
所有人均不在自己座位上的可能机率:0.000%
----------------------------------------------------------------
执行时间99
总人数:1
所有人均不在自己座位上的可能数量:0
所有人均不在自己座位上的可能机率:0.000%
----------------------------------------------------------------
执行时间0
总人数:2
所有人均不在自己座位上的可能数量:1
所有人均不在自己座位上的可能机率:50.000%
----------------------------------------------------------------
执行时间1
总人数:3
所有人均不在自己座位上的可能数量:2
所有人均不在自己座位上的可能机率:33.333%
----------------------------------------------------------------
执行时间8
总人数:4
所有人均不在自己座位上的可能数量:9
所有人均不在自己座位上的可能机率:37.500%
----------------------------------------------------------------
执行时间0
总人数:5
所有人均不在自己座位上的可能数量:44
所有人均不在自己座位上的可能机率:36.667%
----------------------------------------------------------------
执行时间3
总人数:6
所有人均不在自己座位上的可能数量:265
所有人均不在自己座位上的可能机率:36.806%
----------------------------------------------------------------
执行时间15
总人数:7
所有人均不在自己座位上的可能数量:1854
所有人均不在自己座位上的可能机率:36.786%
----------------------------------------------------------------
执行时间92
总人数:8
所有人均不在自己座位上的可能数量:14833
所有人均不在自己座位上的可能机率:36.788%
----------------------------------------------------------------
执行时间253
总人数:9
所有人均不在自己座位上的可能数量:133496
所有人均不在自己座位上的可能机率:36.788%
----------------------------------------------------------------
执行时间1175
总人数:10
所有人均不在自己座位上的可能数量:1334961
所有人均不在自己座位上的可能机率:36.788%
----------------------------------------------------------------
执行时间5210
一楼台的,10个人,执行了40分钟没有结果。现在的,平均执行时间5s左右,根据电脑不同会有不同。
- [原创]10个人都不坐在自己座位上有多少种可能机率多大
- 有n个人和n个座位,求都不坐在自己的位置上的种数
- n个人n个座位,求不能坐在自己座位上种数
- c#编程:有5个人坐在一起,问第5个人多少岁的问题
- 【程序28】有5个人坐在一起,问第五个人多少岁
- 有5个人坐在一起,问第5个人多少岁,答,比第4个人大2岁。。。。。。。。
- HashCode有多大可能重复?
- HashCode有多大可能重复?
- HashCode有多大可能重复?
- 题目:有5个人坐在一起,
- 能对自己下多大狠心,决定你能上多少高度
- 有5个人坐在一起,问第五个人多少岁?他说比第4个人大2岁。问第4个人岁数,他说比第3个人大2岁。问第三个人,又说比第2人大两岁。问第2个人,说比第一个人大两岁。最后问第一个人,他说是10岁。请问第五个
- 题目:有5个人坐在一起,问第五个人多少岁?他说比第4个人大2岁。问第4个人岁数,他说比第3个人大2岁。问第三个人,又说比第2人大两岁。问第2个人,说比第一个人大两岁。最后问第一个人,他说是10岁。请问
- 有5个人ABCDE排队,排好后他们决定重新排队,每个人都不在原来的位置上,那么总共有多少种排法
- 有多大锅下多少米
- 【原创】心有多大,舞台就有多广
- 自己都不坚强,又有谁会在意
- 分享:射击运动员10发打中90环有多少种可能?(C#)
- 解决Shockwave flash在谷歌浏览器上崩溃的问题
- 智能体2月6号记录
- 谷歌浏览器(Chrome)遇到Flash崩溃的处理办法
- 最小割 Stoer-Wagner 算法
- HDOJ 题目2473 Junk-Mail Filter(并查集,删点)
- [原创]10个人都不坐在自己座位上有多少种可能机率多大
- 字符串-04. 字符串逆序(15)
- 字符串-05. 字符串循环左移(20)
- NS3的安装(一)
- 弹出表情气泡&仿魔兽的技能冷效果却实现
- 08-1. 求一批整数中出现最多的个位数字(20)
- Bash 通过上下键更有效的查找历史命令
- HDOJ 2024 C语言合法标识符(水题,讲讲标识符)
- android 关机流程 二