backtracking(回溯算法)

时间:2020-12-15 16:10:23

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

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

  ] = { 'a', 'b', 'c' };     //字串,需要先由小到大排序过
  ];    //用来存放一组可能的答案
  ];        //纪录该字母是否使用过,用过为true

 void  permutation ( int  k ,  int  n )
 {
     // it's a solution
     if  ( k  ==  n )
     {
          ;  i < n ;  i ++)
             cout  <<  solution [ i ];
         cout  <<  endl ;
         return ;                  // if-else改成return
     }

     // 针对solution[i]这个位置,列举所有字母,并各自递回
      ;  i < n ;  i ++)
         if  (! used [ i ])
         {
             used [ i ] =  true ;

             solution [ k ] =  s [ i ];  //填入字母
             permutation ( k +  ,  n );

             used [ i ] =  false ;
         }
 }

字串排列

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

  ] = { 'a', 'b', 'c' };     //字串,需要先由小到大排序过
  ];    //用来存放一组可能的答案
  ];        //纪录该字母是否使用过,用过为true

 void  permutation ( int  k ,  int  n )
 {
     if  ( k  ==  n )  // it's a solution
     {
          ;  i < n ;  i ++)
             cout  <<  solution [ i ];
         cout  <<  endl ;
     }
     else
     {
         // 针对solution[i]这个位置,列举所有字母,并各自递回
          ;  i < n ;  i ++)
             if  (! used [ i ])
             {
                 used [ i ] =  true ;

                 solution [ k ] =  s [ i ];  //填入字母
                 permutation ( k +  ,  n );

                 used [ i ] =  false ;
             }
     }
 }
  ] = { 'a', 'b', 'c' };     //字串,需要先由小到大排序过
  ];    //用来存放一组可能的答案
  ];        //纪录该字母是否使用过,用过为true

 void  permutation ( int  k ,  int  n )
 {
     // it's a solution
     if  ( k  ==  n )
     {
          ;  i < n ;  i ++)
             cout  <<  solution [ i ];
         cout  <<  endl ;
         return ;                  // if-else改成return
     }

     // 针对solution[i]这个位置,列举所有字母,并各自递回
      ;  i < n ;  i ++)
         if  (! used [ i ])
         {
             used [ i ] =  true ;

             solution [ k ] =  s [ i ];  //填入字母
             permutation ( k +  ,  n );

             used [ i ] =  false ;
         }
 }

避免重复排列

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

abb
abb
bab
bba
bab
bba

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

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

  ] = { 'a', 'b', 'b' };     //字串,需要先由小到大排序过
  ];
  ];

 void  permutation ( int  k ,  int  n )
 {
     if  ( k  ==  n )
     {
          ;  i < n ;  i ++)
             cout  <<  solution [ i ];
         cout  <<  endl ;
         return ;
     }

     char  last_letter  =  '\0' ;
      ;  i < n ;  i ++)
         if  (! used [ i ])
             if  ( s [ i ] !=  last_letter )     //避免列举一样的字母
             {
                 last_letter  =  s [ i ];      //纪录刚才使用过的字母
                 used [ i ] =  true ;

                 solution [ k ] =  s [ i ];
                 permutation ( k +  ,  n );

                 used [ i ] =  false ;
             }
 }

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

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

  ] = { 'a', 'b', 'b' };     //字串,需要先由小到大排序过
  ];
  ];

 void  permutation ( int  k ,  int  n )
 {
     if  ( k  ==  n )
     {
          ;  i < n ;  i ++)
             cout  <<  solution [ i ];
         cout  <<  endl ;
         return ;
     }

     char  last_letter  =  '\0' ;
      ;  i < n ;  i ++)
     {                            // if not改成continue
         if  ( used [ i ])  continue ;
         if  ( s [ i ] ==  last_letter )  continue ;   //避免列举一样的字母

         last_letter  =  s [ i ];      //纪录刚才使用过的字母
         used [ i ] =  true ;

         solution [ k ] =  s [ i ];
         permutation ( k +  ,  n );

         used [ i ] =  false ;
     }
 }

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