回溯递归 (写给我的寝室长 曹旭)

来源:互联网 发布:传奇霸业武魂数据 编辑:程序博客网 时间:2024/05/22 08:17

 

下面是很久前我在一论坛看到一帖子,是这篇文章让我回溯递归入门的,上次上一门无聊课时,和寝室长突发雅兴论及递归和回溯来,才想起多年前曾拜读过此文,现整理出来,送与寝室长。望旭哥学术有成,下次再来和小生畅叙。

作为一个程序的初学者,我曾经有一段时间不大理解回朔递归思想。  
当然现在也是不知皮毛的菜鸟。本贴,仅仅给刚入门的学生朋友一点参考。  
希望能让你我对回朔有更进一步的理解。  
   
   
下面开始吧   ^-^:)  

 

int   r   =   4;   
int   n   =   3;   
void   f(int   k)   
{           
    
if(k==r)   
    
{       
        cout   
<<   "hello,world!"   <<   endl;         
        
return;   
    }
         
    
for(int   i=0;   i<n;   i++)         
        f(k
+1);     
    
}
   
int   main()   
{   
    f(
0);   
    cin.
get();           
}
   

 

以上程序会打印多少次:   hello   world!答案是:n^r   次。  
首先:程序从f(0)   进入。在此,我们称f(0)为根结点,并且有n个孩子为f(1)。  
同时每个f(1)结点,又拥有n个孩子结点f(2),依次递归下去。  
但是,我更愿意称,f(i)为第i层,并且该第i层上有n^i个结点(当然f(0)为根,只有一个,为第0层),  
每个结点又有n个孩子结点。所以该题打印的次数就是求f(k)层上结点的个数  
以上就是简单的所谓的解空间树。(下面一段来参考自课本     ·@_@)  

回朔法是系统地搜索问题的所有解的算法。在问题的解空间树中,  
回朔法按照深度优先策略,从根结点出发搜索解空间树。算法搜索至解空间树的任意结点时,先判断该结点是否包含问题的解。如果肯定不包含,那么跳过以该结点为根的子树的搜索,回朔到其双亲,并对该结点的尚未分析的兄弟(如果所有兄弟都分析过,那么则回溯到双亲的尚未分析的兄弟),应用以上的过程。  
否则进入该子树,继续深度优先策略搜索。  
如果要求所有问题的解时,要回朔到根,并且对所有子树都搜索完才结束.  
上面第一个程序幸运的是,所有结点都是包含问题的解。根本不用判断。  


下面来个有点意思的题目。  

 problem1:P(n,r).   从n个数中选取r个数进行全排列(r<=n)。并输出所有解。  
分析:我们可以把n个数看成是一个结点的所有孩子结点。  
因此问题的求解,变成是:从根结点出发搜索所有长度为r的路径。并且要求该路径上任意结点互不相同,因此任意一条该路径上结点的集合就是一个问题的解。  

#include   <iostream.h>   
const   int   n=4;   
const   int   r=3;   
int   flag[n]={0};   
int   result[r]={0};   
void   f(int   k)   
{         
    
if(k==r)//路径长度达到r,输出路径结点。   
    {   
        
for(int   i=0;i<k;i++)   
            cout
<<result[i];   
        cout
<<endl;   
        
return;   
        
    }
   
    
for(int   j=0;j<n;j++)//搜索所有孩子结点   
    {   
        
if(!flag[j])//该结点在路径上尚未被选入   
        {   
            result[k]
=j+1;//记录该结点。   
            flag[j]=1;//表示该结点已经被选中,为了不让其孩子结点与它相同。   
            f(k+1);//进入下一层。   
            flag[j]=0;//以f(k+1)层一结点为根的子树搜索完毕。要回溯到右边的兄弟,要求对做过标记的兄弟恢复。   
        }
   
    }
   
}
   
void   main()   
{   
    f(
0);   
    cin.
get();   
}
 

 

problem2:C(n,r).   从n个数中选取r个数进行组合(r<=n)。并且输出结果。阿哈。怎么样?如何运用以上的策列呢?   

 我们来认真思考一下:首先,路径长度也要为r,不仅路径上的结点要互不相同,同时还要求任意两条路径上的所有结点的集合都要互不相同。 

 

#include   <iostream.h>     
const   int   n=5;   
const   int   r=3;   
int     flag[n]   =   {0};   
int   result[r]={0};   

void   f(int   k)   
{   
    
if(k   ==   r)   
    
{     
        
for(int   i=0;i<k;i++)   
            cout
<<result[i];   
        cout
<<endl;   
        
return;   
    }
   
    
for(int   i=0;   i<n;   i++)   
    
{   
        
if(!flag[i])   
        
{   
            result[k]   
=   i+1;   
            flag[i]   
=   1;   
            f(k
+1);     
            
if(i==n-1)   //以f(k+1)层一结点为根的子树搜索完毕。并且此根是其双亲的最右边的孩子。                               
            {                     //因此要回朔到其双亲的尚未分析的兄弟结点,要求对已经做过标志的右边的兄弟进行恢复。   
                int   s   =   result[k]-result[k-1];//表示要恢复的个数。   
                for(int   j=n-1;   j>=n-s;   j--)   
                    flag[j]   
=   0;   
            }
           
            
        }
               
    }
   
    
}
           
void   main()   
{   
    
    f(
0);   
    cin.
get();   
}
                 

 
problem3:求n个数的所有子集。有了上面两题的分析,这题应该可以轻松解决,:)   (其实这道题在数据结构严蔚敏版有的 刺猬注)

 

 

#include   <iostream.h>   
const   int   n=5;   
int   flag[n]={0};   
int   result[n]={0};   
void   f(int   k)   
{         
    
if(k<=n)   
    
{   
        
for(int   i=0;i<k;i++)   
            cout
<<result[i];   
        cout
<<endl;   
    }
   
    
else   return;   
    
for(int   j=0;j<n;j++)   
    
{   
        
if(!flag[j]&&(j+1>result[k-1]))   
        
{         
            result[k]
=j+1;   
            flag[j]
=1;   
            f(k
+1);   
            flag[j]
=0;   
        }
   
    }
   
}
   
void   main()   
{   
    
    f(
0);   
    cin.
get();   
    
}
   

 

原文地址: http://topic.csdn.net/t/20040810/23/3261786.html

刺猬注:其实我们数据结构教材上专门开辟了一小节叙述回溯与递归的,那里面论述的在看了上面这位前辈所总结之后再去反复咀嚼,才发现其中的奥妙之处,可惜,这节内容太过于“难”,老师也考虑到应试也不多讲。所以对于我们计算机专业,应试基本来说是毫无意义的,拿了一等奖学金其实是骗骗自己,哄哄父母。

高等教育=学校+老师+学生一起来骗世人,或是民族未来?

原创粉丝点击