首页 > 代码库 > backtracking(回溯算法)

backtracking(回溯算法)

http://blog.csdn.net/zxasqwedc/article/details/42270215

permutation的程式码都会长成这样的格式:

技术分享
 1 char  s [ 3 ] = { a, b, c };     //字串,需要先由小到大排序过 2 char  solution [ 3 ];    //用来存放一组可能的答案 3 bool  used [ 3 ];        //纪录该字母是否使用过,用过为true 4   5 void  permutation ( int  k ,  int  n ) 6 { 7     // it‘s a solution 8     if  ( k  ==  n ) 9     {10         for  ( int  i = 0 ;  i < n ;  i ++)11             cout  <<  solution [ i ];12         cout  <<  endl ;13         return ;                  // if-else改成return14     }15     16     // 针对solution[i]这个位置,列举所有字母,并各自递回17     for  ( int  i = 0 ;  i < n ;  i ++)18         if  (! used [ i ])19         {20             used [ i ] =  true ;21  22             solution [ k ] =  s [ i ];  //填入字母23             permutation ( k + 1 ,  n );24  25             used [ i ] =  false ;26         }27 }
View Code

 

字串排列

有个常见的问题是:列出字串abc的所有排列,要依照字典顺序列出。其实这就跟刚才介绍的东西大同小异,只要稍加修改程式码即可。

技术分享
 1 char  s [ 3 ] = { a, b, c };     //字串,需要先由小到大排序过 2 char  solution [ 3 ];    //用来存放一组可能的答案 3 bool  used [ 3 ];        //纪录该字母是否使用过,用过为true 4   5 void  permutation ( int  k ,  int  n ) 6 { 7     if  ( k  ==  n )  // it‘s a solution 8     { 9         for  ( int  i = 0 ;  i < n ;  i ++)10             cout  <<  solution [ i ];11         cout  <<  endl ;12     }13     else14     {15         // 针对solution[i]这个位置,列举所有字母,并各自递回16         for  ( int  i = 0 ;  i < n ;  i ++)17             if  (! used [ i ])18             {19                 used [ i ] =  true ;20  21                 solution [ k ] =  s [ i ];  //填入字母22                 permutation ( k + 1 ,  n );23  24                 used [ i ] =  false ;25             }26     }27 }
View Code

 

技术分享
 1 char  s [ 3 ] = { a, b, c };     //字串,需要先由小到大排序过 2 char  solution [ 3 ];    //用来存放一组可能的答案 3 bool  used [ 3 ];        //纪录该字母是否使用过,用过为true 4   5 void  permutation ( int  k ,  int  n ) 6 { 7     // it‘s a solution 8     if  ( k  ==  n ) 9     {10         for  ( int  i = 0 ;  i < n ;  i ++)11             cout  <<  solution [ i ];12         cout  <<  endl ;13         return ;                  // if-else改成return14     }15     16     // 针对solution[i]这个位置,列举所有字母,并各自递回17     for  ( int  i = 0 ;  i < n ;  i ++)18         if  (! used [ i ])19         {20             used [ i ] =  true ;21  22             solution [ k ] =  s [ i ];  //填入字母23             permutation ( k + 1 ,  n );24  25             used [ i ] =  false ;26         }27 }
View Code

 

避免重复排列

若是字串排列的问题改成:列出abb的所有排列,依照字典顺序列出。答案应该为abb、aba、baa。不过使用刚刚的程式码的话,答案却会变成这样:

abbabbbabbbababbba

这跟预期的不一样。会有这种结果,是由于之前的程式有个基本假设:字串中的每个字母都不一样。尽管出现了一样的字母,但是程式还是把它当作是不一样的字母,依旧把所有可能的排列都列出,也就是现在的结果──有一些排列重复出现了。

要解决问题,在列举某一个位置的字母时,就必须避免一直填入一样的字母。如此就可以避免产生重复的排列。

 

技术分享
 1 char  s [ 3 ] = { a, b, b };     //字串,需要先由小到大排序过 2 char  solution [ 3 ]; 3 bool  used [ 3 ]; 4   5 void  permutation ( int  k ,  int  n ) 6 { 7     if  ( k  ==  n ) 8     { 9         for  ( int  i = 0 ;  i < n ;  i ++)10             cout  <<  solution [ i ];11         cout  <<  endl ;12         return ;13     }14     15     char  last_letter  =  \0 ;16     for  ( int  i = 0 ;  i < n ;  i ++)17         if  (! used [ i ])18             if  ( s [ i ] !=  last_letter )     //避免列举一样的字母19             {20                 last_letter  =  s [ i ];      //纪录刚才使用过的字母21                 used [ i ] =  true ;22  23                 solution [ k ] =  s [ i ];24                 permutation ( k + 1 ,  n );25  26                 used [ i ] =  false ;27             }28 }
View Code

 

因为输入的字串由小到大排序过,字母会依照顺序出现,所以只要检查上一个使用过的字母,判断一不一样之后,就可以避免列举一样的字母了。

程式码也可以改写成这种风格:

技术分享
 1 char  s [ 3 ] = { a, b, b };     //字串,需要先由小到大排序过 2 char  solution [ 3 ]; 3 bool  used [ 3 ]; 4   5 void  permutation ( int  k ,  int  n ) 6 { 7     if  ( k  ==  n ) 8     { 9         for  ( int  i = 0 ;  i < n ;  i ++)10             cout  <<  solution [ i ];11         cout  <<  endl ;12         return ;13     }14     15     char  last_letter  =  \0 ;16     for  ( int  i = 0 ;  i < n ;  i ++)17     {                            // if not改成continue18         if  ( used [ i ])  continue ;19         if  ( s [ i ] ==  last_letter )  continue ;   //避免列举一样的字母20  21         last_letter  =  s [ i ];      //纪录刚才使用过的字母22         used [ i ] =  true ;23  24         solution [ k ] =  s [ i ];25         permutation ( k + 1 ,  n );26  27         used [ i ] =  false ;28     }29 }
View Code

 

http://www.cnblogs.com/guxuanqing/p/5602028.html

backtracking(回溯算法)