不容易系列之(4)——考新郎 HDU - 2049 (递推—错排—组合数)

题目:

Description
国庆期间,省城HZ刚刚举行了一场盛大的集体婚礼,为了使婚礼进行的丰富一些,司仪临时想出了有一个有意思的节目,叫做"考新郎",具体的操作是这样的:
首先,给每位新娘打扮得几乎一模一样,并盖上大大的红盖头随机坐成一排;
然后,让各位新郎寻找自己的新娘.每人只准找一个,并且不允许多人找一个.
最后,揭开盖头,如果找错了对象就要当众跪搓衣板…
假设一共有N对新婚夫妇,其中有M个新郎找错了新娘,求发生这种情况一共有多少种可能.
Input
输入数据的第一行是一个整数C,表示测试实例的个数,然后是C行数据,每行包含两个整数N和M(1<M<=N<=20)。
Output
对于每个测试实例,请输出一共有多少种发生这种情况的可能,每个实例的输出占一行。
Sample Input
2
2 2
3 2
Sample Output
1
3
Source
https://vjudge.net/problem/HDU-2049

思路:

N个新郎选N个新娘,其中选错了M个,那么结果种数可以表示为: (N个里选M个的选法种数) × (M个错排的排列种数)

那我们只需解决两个问题:
1.N个里选M个是组合数的问题,求出 C(N,M) 即可,为了提高效率我们可以预处理求出所有组合数的值
2.M个错排:因为新郎和新娘是一一映射的关系,M个错排即M个新郎均找错了新娘 哎呦太惨了
我们把 M 分成 M-1 和 1 两部分,那么就可看作: M-1 对新郎新娘匹配完(未必符合错排)后,再加入一对新郎新娘。这时仅有两种情况符合 M 个错排的要求,下表中 d[X] 为 X 个错排的种数,本质还是递推求解:

情况: M-1 已错排 M-1 未错排但 M-2 已错排(有1个匹配到了自己的新娘)
如何实现M个错排 新加入的新郎用她的新娘和任意一个新郎错排列 M-1个人里有一个匹配对了,新加入的新郎只能与其交换
表达式 d[M-1] * (M-1) (M-1) * d[M-2]

表中两式相加再乘上C(N,M)即 d[M],求得。其实本题有两个预处理

实现:

int main() {int T; cin >> T; getchar();
    LL n, m, c[25][25]={0}, d[25], ans;
    for(n = 1; n <= 20; n++)
        c[n][0] = 1, c[n][n] = 1;

    for(n = 2; n <= 20; n++)
        for(m = 1; m <= (n+1)/2; m++) { //组合数预处理
            c[n][m] = c[n-1][m] + c[n-1][m-1];
            c[n][n-m] = c[n][m];
        }
    d[1] = 0; d[2] = 1;
    for(m = 2; m < 20; m++)
        d[m+1] = (d[m] + d[m-1]) * m; //错排预处理

    while(T--) {
        cin >> n >> m;
        cout << c[n][m] * d[m] << endl;
    }
    return 0;
}

在这里插入图片描述

发布了54 篇原创文章 · 获赞 43 · 访问量 1940

猜你喜欢

转载自blog.csdn.net/Jungle_st/article/details/104714594