错排问题-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;
	}
}
  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值