錯排問題-C++實現

錯排問題是組合數學中的問題之一。考慮一個有n個元素的排列,若一個排列中所有的元素都不在自己原來的位置上,那麼這樣的排列就稱爲原排列的一個錯排。 n個元素的錯排數記爲Dn。 研究一個排列錯排個數的問題,叫做錯排問題或稱爲更列問題。
最早研究錯排問題的是尼古拉·伯努利和歐拉,因此歷史上也稱爲伯努利-歐拉的裝錯信封的問題。這個問題有許多具體的版本,如在寫信時將n封信裝到n個不同的信封裏,有多少種全部裝錯信封的情況?又比如四人各寫一張賀年卡互相贈送,有多少種贈送方法?自己寫的賀年卡不能送給自己,所以也是典型的錯排問題。

枚舉法 對於情況較少的排列,可以使用枚舉法。

當n=1時,全排列只有一種,不是錯排,D1 = 0。

當n=2時,全排列有兩種,即1、2和2、1,後者是錯排,D2 = 1。

當n=3時,全排列有六種,即1、2、3;1、3、2;2、1、3;2、3、1;3、1、2;3、2、1,其中只有有3、1、2和2、3、1是錯排,D3=2。用同樣的方法可以知道D4=9。

最小的幾個錯排數是:D1 = 0,D2 = 1,D3=2,D4 = 9,D5 = 44,D6 = 265,D7 = 1854.

用f(n)表示n對鎖,全部排錯的可能性。
對於一對鎖,不存在錯誤,有f(1)=0;
對於兩對鎖,錯排有1種情況,有f(2)=1;
對於三對鎖,錯排有2種情況,有f(3)=2;
對於四對鎖,錯排有9種情況,有f(4)=9;
以上四種,自己寫寫畫畫都能出的來,當鎖的數量增加時,就不那麼容易了,下面用遞推的思路進行計算,具體計算就交給計算機來完成啦。
對於五對鎖,分析如下:
全部的排列可能性爲5!
只有一對鎖配對正確,其餘四對配對全部錯誤,數量爲C(4,1)×f(4);
只有兩對鎖配對正確,其餘三對配對全部錯誤,數量爲C(4,2)×f(3);
只有三對鎖配對正確????那豈不是四對全部都正確了。。。數量爲1。
所以:五對鎖全部配對錯誤的數量爲:5!-C(4,1)×f(4)-C(4,2)×f(3)-1
對於n對鎖,分析情況類似五對鎖。
全部排列可能性爲n!;
只有一對鎖配對正確,其餘n-1對鎖配對全部錯誤,數量爲C(n,1)×f(n-1);
只有兩對鎖配對正確,其餘n-2對鎖配對全部錯誤,數量爲C(n,2)×f(n-2);
只有三對鎖配對正確,其餘n-3對鎖配對全部錯誤,數量爲C(n,3)×f(n-3);
。。。
只有n-2對鎖配對正確,其餘2對鎖配對全部錯誤,數量爲C(n,n-2)×f(2);
只有n-1對鎖配對正確,那最後一對肯定也正確,數量爲1.
所以:n對鎖全部配對錯誤的數量爲:
n!-C(n,1)×f(n-1)-C(n,2)×f(n-2)-C(n,3)×f(n-3)-……-C(n,n-2)×f(2)-1

作者:BridgeLiang
鏈接:https://www.zhihu.com/question/24824657/answer/29159212
來源:知乎
著作權歸作者所有。商業轉載請聯繫作者獲得授權,非商業轉載請註明出處。

#define ll int
#define vec vector<ll>
#define inf 0x3f3f3f3f
#define MAX 22
#define MOD 2333333

long long C[MAX][MAX], dp[MAX];//C[i][j]:在i個裏面取j個

int main() {
	for (int i = 1; i < MAX; i++) {
		C[i][i] = C[i][0] = 1;
		for (int j = 1; j < i; j++) {
			C[i][j] = C[i - 1][j] + C[i - 1][j - 1];
		}
	}
	dp[0] = 1; dp[1] = 0, dp[2] = 1, dp[3] = 2;//dp[i]:i個物品錯排的組合數
	long long b = 6;
	for (int i = 4; i < MAX; i++) {
		b *= i; dp[i] = b;
		for (int j = 1; j <= i; j++)
			dp[i] -= C[i][j] * dp[i - j];
	}
	int n, t; cin >> n;
	while (n--) {
		cin >> t;
		cout << dp[t] << endl;
	}
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章