完全错排问题

题目链接:http://acm.nyist.net/JudgeOnline/problem.php?pid=451

就是求C(n, n-m)*s(m)的值啦,C(n, n-m)表示从n个人中任取n-m个人的组合数,s(m)表示m对人和纸条的完全错排种数;

组合数求法很简单就不细说了,推一下完全错排计算公式好了;

假设现在有编号1~m的m个求和编号1~m的m个盒子,将m个求均分到m个盒子中,且1号球不能放1号盒子,2号球不能放2号盒子。。。(m个球完全错排);

用s(m)表示m个球的完全错排方法数;

假设先放1号球,可以放编号2~m的盒子,有m-1种放法(先放任意编号的球都是一样的),假设后面m-1个球有a中放法,则s(m)=(m-1)*a;

假设1号球放在2号盒子里,接下来我们考虑:

  (1):假设2号球放在1号盒子里,剩余的球有s(m-2)种放法;

  (2):假设2号球不放1号盒子里,这时我们可以将1号盒子和2号盒子换下位子,(因为2号球不放1号盒子,所以我们可以把1号盒子当做2号盒子来看,这点比较难理解但很关键),

     于是我们可以得到剩余的球有s(m-1)种放法;

所以a=s(m-1)+s(m-2);

即:s(m)=(m-1)*(s(m-1)*s(m-2);

代码:

 1 #include <bits/stdc++.h>
 2 #define MAXN 20+10
 3 #define ll long long
 4 using namespace std;
 5 
 6 ll cc(ll n, ll m){
 7     ll ans=1; 
 8     for(ll i=n, k=1; k<=m; k++, i--){
 9         ans*=i;
10     }
11     for(int i=1; i<=m; i++){
12         ans/=i;
13     }
14     return ans;
15 }
16 
17 int main(void){
18     ll n, m, a[MAXN];
19     a[2]=1, a[3]=2;
20     for(int i=4; i<MAXN; i++){
21         a[i]=(i-1)*(a[i-1]+a[i-2]);
22     }
23     while(scanf("%lld%lld", &n, &m)!=EOF){
24         ll ans=cc(n, n-m)*a[m];
25         cout << ans << endl;
26     }
27     return 0;
28 }
原文地址:https://www.cnblogs.com/geloutingyu/p/5943953.html