[原创]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左右,根据电脑不同会有不同。
0 0
原创粉丝点击