[原創]10個人都不坐在自己座位上有多少種可能機率多大
阿新 • • 發佈:2019-02-12
優化後的程式碼,可以算出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個人的時候的機率,這也只能算出來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左右,根據電腦不同會有不同。