经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 程序设计 » C++ » 查看文章
递归入门——错排及其应用
来源:cnblogs  作者:Trirabbits三兔  时间:2018/12/13 9:33:27  对本文有异议

一、常见递归

? 简单题:母牛的故事骨牌铺方格一只小蜜蜂...

? 中等题:不容易系列之(3)—— LELE的RPG难题阿牛的EOF牛肉串

? 较难题:神、上帝以及老天爷不容易系列之(4)——考新郎

? 变态题:折线分割平面

? 简单题,显而易见的规律;中等题,略加思考推出来的规律;较难题,深度思考(其实是我高中数学弱,不会错排??????);变态题,我想不出来,看题解也没看懂的题。

二、递推公式:斐波那契型

\[ F(n) = F(n-1) + F(n-2) \]

? 上述题目除了折线分割平面之外,都是这个公式的变形。

较难题需要用到错排,今天细讲错排。

三、错排公式的推导和应用

错排的定义:一段序列中一共有n个元素,那么可知这些元素一共有n!种排列方法。假如在进行排列时,原来所有的元素都不在原来的位置,那么称这个排列为错排。而错排数所指的就是在一段有n个元素的序列中,有多少种排列方式是错排。
\[ 递归关系:D(n)=(n-1)(D(n-1)+D(n-2)) 特别地有D(1)=0,D(2)=1; \\错排公式:D(n)=(n!)[(-1)^0/0!+(-1)^1/(1!)+(-1)^2/(2!) +(-1)^3/(3!)+......+(-1)^n/(n!)]; \\其中n!=n*(n-1)*(n-2)*......3*2*1 特别地有0!=1\quad 1!=1 \]

递推思想:


? 一共分为两步

第一步:

? 错排(不能选择自己本来就在的位置)第一个元素,在n个位置中任选一个位置,有 n-1 种选法。

第二步:

? 错排其余n-1个元素,也是需要分情况和种类的。因为这需要看第一步的结果,如果第一个元素落在第k个位置上,第二步就需要把k号元素进行错排,k号元素错排位置的不同将导致不同的情况会发生:

.假设k号元素正好落在了第一个元素的位置,那么就可以将第一个元素和第k个元素完全剔除出去,因为相当于只是他们两者互换了位置,其他元素暂时还没有发生变动。留下来的n-2元素进行错排的话,那么我们就可以得到了D(n-2)种 的错排方式。

.若k号元素不排到第一个元素的位置,我们可以暂时将现在排在k号位置的第一个元素剔除出去,生下来的就只包含k号元素和原来n-2个的元素了。这时,我们可以将原来的第一个元素的位置看做是现在k号元素的原本位置,因为k号元素不能够放在原来的位置上,所以就相当于是原来的n-2个元素和k共计n-1个元素进行完全的错排。那么一共就有D(n-1)种方法。

综上所述:第二步得到D(n-1)+D(n-2)种方法,第一步是n-1种,由于是分步进行,所以结果为(n-1)*[D(n-1)+D(n-2)]种方法。

四、实战

神、上帝以及老天爷

? 典型的错排题目神、上帝以及老天爷,这道题的题意就是求所有的组合情况中错排所占的比例,题目要求的就是这个。
\[ \frac{(n-1)*[D(n-1)+D(n-2)]}{N!} \]
下面就是AC代码了:

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. int main()
  4. {
  5. int t;
  6. int s;
  7. double a[20+5] = {0,0,1}; //错排的数组
  8. double b[20+5] = {2,2,2}; //全排的数组
  9. int i = 3;
  10. cin >> t;
  11. while(t--)
  12. {
  13. cin >> s;
  14. for( ; i <= s; i++)
  15. {
  16. a[i] = (i-1)*(a[i-1]+a[i-2]); //错排
  17. b[i] = b[i-1]*i; //全排
  18. }
  19. cout << fixed << setprecision(2) << a[s]/b[s]*100 << "%" << endl;
  20. }
  21. }

不容易系列之(4)——考新郎

? 这道题的题意为在n对新人里面挑出m对新人来错排,那么实际让我们求得就是挑出m对新人的方法乘以m对新人的错排方法。就是下面这个公式。
\[ C_n ^m*(n-1)*[D(n-1)+D(n-2)] \]
下面是AC代码:

  1. #include <bits/stdc++.h>
  2. typedef long long ll;
  3. using namespace std;
  4. ll factorial(int n, int m) //求组合数
  5. {
  6. ll ans = 1;
  7. if(m < n-m)
  8. m = n-m;
  9. for(int i = m+1; i <= n; i++)
  10. ans *= i;
  11. for(int j = 1; j <= n - m; j++)
  12. ans /= j;
  13. return ans;
  14. }
  15. int main()
  16. {
  17. int t;
  18. int n, m;
  19. ll a[20+5] = {0,0,1};
  20. int i = 3;
  21. int temp;
  22. cin >> t;
  23. while(t--)
  24. {
  25. cin >> n >> m;
  26. if( n < m)
  27. {
  28. temp = n;
  29. n = m;
  30. m = temp;
  31. }
  32. for( ; i <= m; i++) //错排
  33. a[i] = (i-1)*(a[i-1]+a[i-2]);
  34. cout << factorial(n,m)*a[m] << endl;//输出错排*组合数
  35. }
  36. }

求组合数代码(用阶乘不到20就超出long long的范围了):

  1. typedef long long ll;
  2. ll factorial(int n, int m) //求组合数
  3. {
  4. ll ans = 1;
  5. if(m < n-m)
  6. m = n-m;
  7. for(int i = m+1; i <= n; i++)
  8. ans *= i;
  9. for(int j = 1; j <= n - m; j++)
  10. ans /= j;
  11. return ans;
  12. }
 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号