题目描述
过年期间,老家举行了一场盛大的集体婚礼,为了使婚礼进行的丰富一些,司仪临时想出了有一个有意思的节目,叫做“考新郎”,具体的操作是这样的:
- 首先,给每位新娘打扮得几乎一模一样,并盖上大大的红盖头随机坐成一排;
- 然后,让各位新郎寻找自己的新娘。每人只准找一个,并且不允许多人找一个;
- 最后,揭开盖头,如果找错了对象就要当众跪搓衣板…
假设一共有n对新婚夫妇,其中有m个新郎找错了新娘,求发生这种情况一共有多少种可能。
输入描述:
输入包含多组数据。每组数据包含两个正整数n和m(2≤m≤n≤20)
输出描述:
对应每一组数据,输出一个正整数,表示n对新人中有m个新郎找错新娘的种数。
输入例子:
2 2
3 2
输出例子:
1
3
首先我们需要从n对夫妻中选出m对夫妻,总共有Cm,n=n!/m!/(n - m)!
种情况。
接着这m对夫妻的新郎全部选错的情况f(m) = (m - 1) * (f(m - 1) * f(m - 2))
,这个公式上前面好几道都推过,请参考我的博客 PAT乙级(Basic Level)练习题 发邮件
因此公式为:n!/m!/(n - m)! * f(m)
#include <iostream>
using namespace std;
int main() {
int m = 0, n = 0;
//fTable[n]记录n个人都悬错的情况种数,allTable[n]记录n的阶乘
long long fTable[21] = {0, 0, 1}, allTable[21] = {1, 1, 2};
for (int i = 3; i < 21; ++i) {
//递推计算i个人全部拿错
fTable[i] = (i - 1) * (fTable[i - 1] + fTable[i - 2]);
//递推计算i的阶乘
allTable[i] = i * allTable[i - 1];
}
//scanf返回值为正确输入数据的变量个数,当一个变量都没有成功获取数据时,此时返回-1
while (scanf("%d %d", &n, &m) != - 1) {
//组合公式Cm,n=n!/m!/(n - m)!,从n个中随机s选m个
//从n对中选出m对,allTable[n] / allTable[m] /allTable[n - m]情况
//选出的m对夫妻全部选错,fTable[m]种情况
printf("%lld\n", allTable[n] / allTable[m] /allTable[n - m] * fTable[m]);
}
return 0;
}