过年期间,老家举行了一场盛大的集体婚礼,为了使婚礼进行的丰富一些,司仪临时想出了有一个有意思的节目,叫做“考新郎”,具体的操作是这样的:
1. 首先,给每位新娘打扮得几乎一模一样,并盖上大大的红盖头随机坐成一排;
2. 然后,让各位新郎寻找自己的新娘。每人只准找一个,并且不允许多人找一个;
3. 最后,揭开盖头,如果找错了对象就要当众跪搓衣板...
假设一共有n对新婚夫妇,其中有m个新郎找错了新娘,求发生这种情况一共有多少种可能。
输入包含多组数据。每组数据包含两个正整数n和m(2≤m≤n≤20)
对应每一组数据,输出一个正整数,表示n对新人中有m个新郎找错新娘的种数。
2 2<br/>3 2
1<br/>3
#include <iostream> #include <stdio.h> #define N 21 using namespace std; int main() { long long f[N] = {1, 0, 1}; long long fac[N] = {1, 1, 2}; for(int i=3; i<N; i++) { f[i] = (i-1)*(f[i-1] + f[i-2]); fac[i] = i*fac[i-1]; } int n, m; while(~scanf("%d %d", &n, &m)) { printf("%lld\n", fac[n]/fac[m]/fac[n-m]*f[m]); } return 0; }
import sys
from math import factorial as f
#求错位数的函数
def dislocationNumber(n):
arr = [0, 1]
while len(arr) < n:
arr.append(len(arr) * (arr[-1] + arr[-2]))
return arr[-1]
for i in sys.stdin.readlines():
n, m = map(int, i.strip().split())
print(dislocationNumber(m) * f(n) // (f(m) * f(n - m)))
首先我们需要从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;
}
————————————————
版权声明:本文为CSDN博主「hestyle」的原创文章,遵循 CC 4.0 BY 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://hestyle.blog.csdn.net/article/details/104690822
import java.math.BigInteger;
import java.util.*;
public class Main{
public static void main(String[] args){
Scanner sc=new Scanner(System.in);
BigInteger[] der=new BigInteger[21];
der[0]=new BigInteger("0");
der[1]=new BigInteger("0");
der[2]=new BigInteger("1");
for(int i=3;i<21;i++){
der[i]=(der[i-2].add(der[i-1])).multiply(new BigInteger(i-1+""));
}
while(sc.hasNext()){
int n=sc.nextInt();
int m=sc.nextInt();
System.out.println(der[m].multiply(jiechen(n)).divide(jiechen(m).multiply(jiechen(n-m))));
}
}
public static BigInteger jiechen(int n){
BigInteger result=new BigInteger("1");
for(int i=2;i<=n;i++){
result=result.multiply(new BigInteger(i+""));
}
return result;
}
}
f[i][j]表示有i对新婚夫妇有j个新郎找错新娘的种数
容易知道当前有i - 1对新婚夫妇时加一对新婚夫妇进来时无非有三种情况:
1)加进来的新郎找对了,该有多少人找错还是有多少人找错 --> f[i][j] += f[i - 1][j]
2)加进来的新郎与前i - 1个中找对的新郎互换,找错对数加2 -->f[i][j] += f[i - 1][j - 2] * (i - 1 - (j - 2))
3)加进来的新郎与前i - 1个中找错的新郎互换-,找错对数加1 -->f[i][j] += f[i - 1][j - 1] * (j - 1)
//n个中取m个,对m个错排
#include <stdio.h>
#include <stdlib.h>
long long int find[21] = {0, 0, 1, 2};
long long int func[20] = {1, 1, 2, 6};
//n!/(m!(n-m)!)
long long int fun(int);
int main()
{
int i;
for(i = 3; i < 21; i++)
{
find[i] = (i-1) * (find[i-1] + find[i-2]);
func[i] = fun(i);
}
int m, n;
while(~scanf("%d %d", &n, &m))
{
long long int result = find[m] * (func[n] / (func[m] * func[n-m]));
printf("%lld\n", result);
}
}
long long int fun(int i)
{
if(i == 0 || i == 1)
return 1;
return i * fun(i-1)
def cal(a,b): con1,con2 = 1,1 for i in range(1,b+1): con1 = con1*i for i in range(a,a-b,-1): con2 = con2*i return con2//con1*f[b] f = [0,0,1]+[0 for i in range(3,21)] for i in range(3,21): f[i] = (i-1)*(f[i-1]+f[i-2]) try: while True: n,m = map(int,input().split()) print(cal(n,m)) except: pass
思路 : 本质上是信封问题。和排列组合问题的组合
#include <vector>
#include <iostream>
using namespace std;
vector<long long> v(22);
long long Fac(int n)
{
register long long f = 1;
while (n != 1 && n > 0)
{
f *= n;
n--;
}
return f;
}
long long C_n_m(int n, int m)
{
return Fac(n) / (Fac(n - m) * Fac(m));
}
int main()
{
v[0] = 0;
v[1] = 0;
v[2] = 1;
for (int i = 3; i < 21; i++)
{
v[i] = (i - 1)*(v[i - 1] + v[i - 2]);
}
int n, m;
while (cin >> n >> m)
{
long long temp = n - m;
temp = C_n_m(n, m)*v[m];
cout << temp << endl;
}
return 0;
}
import java.util.Scanner;
public class Main {
public static long fn(int m){
if(m == 1){
return 0;
}else if(m == 2){
return 1;
}else{
return (m-1)*(fn(m-1)+fn(m-2));
}
}
public static long JieCheng(int n){
long num = 1;
for(int i=n;i>=1;i--){
num = num * i;
}
return num;
}
public static long C(int n,int m){
long part1 = JieCheng(n);
long part2 = JieCheng(m);
long part3 = JieCheng(n - m);
return part1 / (part2 * part3);
}
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
while(sc.hasNext()){
int n = sc.nextInt();
int m = sc.nextInt();
long result = C(n,m)*fn(m);
System.out.println(result);
}
}
}
只是变式的错排问题而已,无非多了一个组合数~
#include<stdio.h>
long long jiecheng(int n)
{
long long ans=1;
int i;
for(i=1;i<=n;i++)
ans*=i;
return ans;
}
long long C(int n,int m)
{
return jiecheng(n)/(jiecheng(n-m)*jiecheng(m));
}
int main()
{
long long f[22];
int i,m,n;
f[1]=0;f[2]=1;
for(i=3;i<=21;i++)
{
f[i]=(i-1)*(f[i-1]+f[i-2]);
}
while(~scanf("%d%d",&n,&m))
{
printf("%lld\n",C(n,m)*f[m]);
}
return 0;
}
#include <stdio.h>
long long all(int n){
if(n==2)
return 1;
if(n==3)
return 2;
else{
return (all(n-1)+all(n-2))*(n-1);
}
}
int main()
{
int m,n,i;
while(scanf("%d %d",&n,&m)!=EOF){
long long ms=1;
long long ns=1;
long long mns=1;
long long s=all(m);
if(m==n){
printf("%lld\n",s);
}else{
for(i=1;i<=n;i++){
ns*=i;
}
for(i=1;i<=m;i++){
ms*=i;
}
for(i=1;i<=(n-m);i++){
mns*=i;
}
printf("%lld\n",ns/ms/mns*s);
}
}
return 0;
}