01算法笔记——【递归】排列问题,整数划分问题,Hanoi问题

来源:互联网 发布:mac制作手机铃声 编辑:程序博客网 时间:2024/06/16 04:32

递归的概念想必大家都清楚,概念神马的直接略过。这里介绍递归相关的几个问题。

    1、排列问题

    设R={r1,r2,...,rn}是要进行排列的n个元素,Ri=R-{ri}。集合x中元素的全排列记为Perm(X)。(ri)Perm(X)表示在全排列Perm(X)的每一个排列前加上前缀ri得到的排列。R的全排列可归纳如下:

    当n=1时,Perm(R)=(r),其中r是集合中唯一的元素;

    当n>1时,Perm(R)由(r1)Perm(R1),(r2)Perm(R2),(r3)Perm(R3)。。。。(rn)Perm(Rn)构成。

    程序代码:

[cpp] view plaincopy
  1. //2-4 排列问题  
  2. #include "stdafx.h"  
  3. #include <iostream>       
  4. using namespace std;   
  5.   
  6. template <class Type>  
  7. inline void Swap(Type &a,Type &b);  
  8.   
  9. template <class Type>  
  10. void Perm(Type list[],int k,int m);  
  11.   
  12. int main()  
  13. {  
  14.     int list[3];  
  15.     for(int i=0; i<3;i++)  
  16.     {  
  17.         list[i] = i+1;  
  18.     }  
  19.     Perm(list,0,2);  
  20.     return 0;  
  21. }  
  22.   
  23. template <class Type>  
  24. inline void Swap(Type &a,Type &b)  
  25. {  
  26.     Type temp = a;  
  27.     a = b;  
  28.     b = temp;  
  29. }  
  30.   
  31. template <class Type>  
  32. void Perm(Type list[],int k,int m)  
  33. {  
  34.     //只剩下一个元素  
  35.     if(k == m){  
  36.         for(int i=0; i<=m; i++)  
  37.         {  
  38.             cout<<list[i]<<" ";  
  39.         }  
  40.         cout<<endl;  
  41.     }  
  42.     else  
  43.     {  
  44.         //将list[k:m}中的每一个元素分别与list[k]中的元素交换  
  45.         //然后递归计算list[k+1:m]的全排列,将计算结果作为list[0:k]后缀  
  46.         for(int i=k; i<=m;i++){  
  47.             Swap(list[k],list[i]);  
  48.             Perm(list,k+1,m);  
  49.             Swap(list[k],list[i]);  
  50.         }  
  51.     }  
  52. }  

       运行结果:



2、整数划分问题

    将正整数n表示成一系列正整数之和,n=n1+n2+n3+......nk(其中,n1>=n2>=......nk>=1,k>=1),正整数n的这种表示称为正整数n的划分。正整数n的不同划分个数称为正整数n的划分数,记作p(n)。例如:正整数6有11总不同的划分

6;

5+1;

4+2,4+1+1;

3+3,3+2+1,3+1+1+1;

2+2+2,2+2+1+1,2+1+1+1+1;

1+1+1+1+1+1;

记q(n,m)为正整数n的所有不同划分中,最大加数n1不大于m的划分个数。可以建立如下递推关系:

前面三个递推式比较好理解,关键是第四个递推式。当n>m>1时,n的划分由两部分组成。以整数q(6,3)为例,q(n,m-1)内容是第5排和第6排内容,不大于2的6的划分;q(n-m,m)内容是第4排,不大于3的(6-3=3)的划分。

程序代码:

[cpp] view plaincopy
  1. //2-4 整数划分问题  
  2. #include "stdafx.h"  
  3. #include <iostream>       
  4. using namespace std;  
  5.   
  6. int q(int n,int m);  
  7.   
  8. int main(){  
  9.     cout<<q(6,6)<<endl;  
  10.     return 0;  
  11. }  
  12.   
  13. int q(int n,int m)  
  14. {  
  15.     if( n<1 || m<1)  
  16.     {  
  17.         return 0;  
  18.     }  
  19.     else if(n==1 || m==1)  
  20.     {  
  21.         return 1;  
  22.     }  
  23.     else if(n<m)  
  24.     {  
  25.         return q(n,n);  
  26.     }  
  27.     else if(n==m)  
  28.     {  
  29.         return q(n,m-1) + 1;  
  30.     }  
  31.     else  
  32.     {  
  33.         return q(n,m-1) + q(n-m,m);  
  34.     }  
  35. }  

3、汉诺塔问题

     这个问题大家都比较熟悉。这里直接给出程序清单。

[cpp] view plaincopy
  1. //2-6 Hanoi问题  
  2. #include "stdafx.h"  
  3. #include <iostream>       
  4. using namespace std;  
  5.   
  6. void hanoi(int n,char a,char b,char c);  
  7.   
  8. int main(){  
  9.     char a = 'A',b = 'B',c='C';  
  10.     hanoi(3,a,b,c);  
  11.     return 0;  
  12. }  
  13.   
  14. //借助c,将n个盘子从a移到b  
  15. void hanoi(int n,char a,char b,char c)  
  16. {  
  17.     if(n>0)  
  18.     {  
  19.         hanoi(n-1,a,c,b);//借助b,将n-1个盘子从a移到c  
  20.         cout<<"将"<<a<<"中最大的盘子从"<<a<<"移到"<<b<<endl;  
  21.         hanoi(n-1,c,b,a);//借助a,将n-1个盘子从c移到b  
  22.     }  
  23. }  

 

0 0