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改成return
14     }
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 }

字串排列

有个常见的问题是:列出字串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     else
14     {
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 }

 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改成return
14     }
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 }

避免重复排列

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

abb
abb
bab
bba
bab
bba

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

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

 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 }

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

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

 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改成continue
18         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 }

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

时间: 2024-10-14 08:59:23

backtracking(回溯算法)的相关文章

穷举递归和回溯算法终结篇

穷举递归和回溯算法 在一般的递归函数中,如二分查找.反转文件等,在每个决策点只需要调用一个递归(比如在二分查找,在每个节点我们只需要选择递归左子树或者右子树),在这样的递归调用中,递归调用形成了一个线性结构,而算法的性能取决于调用函数的栈深度.比如对于反转文件,调用栈的深度等于文件的大小:再比如二分查找,递归深度为O(nlogn),这两类递归调用都非常高效. 现在考虑子集问题或者全排列问题,在每一个决策点我们不在只是选择一个分支进行递归调用,而是要尝试所有的分支进行递归调用.在每一个决策点有多种

8皇后以及N皇后算法探究,回溯算法的JAVA实现,非递归,循环控制及其优化

上两篇博客 8皇后以及N皇后算法探究,回溯算法的JAVA实现,递归方案 8皇后以及N皇后算法探究,回溯算法的JAVA实现,非递归,数据结构“栈”实现 研究了递归方法实现回溯,解决N皇后问题,下面我们来探讨一下非递归方案 实验结果令人还是有些失望,原来非递归方案的性能并不比递归方案性能高 代码如下: package com.newflypig.eightqueen; import java.util.Date; /** * 使用循环控制来实现回溯,解决N皇后 * @author [email pr

回溯0--递归回溯算法框架

递归回溯算法框架 一.心得 3 都是在for下的if下的 4 保存结果,找下一步,回溯,这三个是一起的 5 还有一个到达目的地输出解放在外面就好 search后面的k是轮数  三个数组:原数据数组标记数组储存结果数组 框架二 到目的地的情况要多加1,因为满足了的下一轮就好判断 二.代码 1 /* 2 递归回溯算法框架: 3 都是在for下的if下的 4 保存结果,找下一步,回溯,这三个是一起的 5 还有一个到达目的地输出解放在外面就好 6 */ 7 /* 8 框架一 9 */ 10 int se

回溯算法解八皇后问题(java版)

八皇后问题是学习回溯算法时不得不提的一个问题,用回溯算法解决该问题逻辑比较简单. 下面用java版的回溯算法来解决八皇后问题. 八皇后问题,是一个古老而著名的问题,是回溯算法的典型案例.该问题是国际西洋棋棋手马克斯·贝瑟尔于1848年提出:在8×8格的国际象棋上摆放八个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行.同一列或同一斜线上,问有多少种摆法. 思路是按行来规定皇后,第一行放第一个皇后,第二行放第二个,然后通过遍历所有列,来判断下一个皇后能否放在该列.直到所有皇后都放完,或者放哪

数据结构之回溯算法

借鉴:http://blog.csdn.net/baple/article/details/7181404 package database; public class NQuee { public static boolean Verify(int arr[],int i){                              //仅仅判断能不能放置这个皇后        for(int k =1;k != i;k++)                                  

【八皇后问题】 回溯算法

回溯算法:回溯算法实际上是一个类似枚举的搜索尝试方法,它的思想是在搜索尝试中寻找问题的解,当发现不满足求解条件时,就“回溯”返回,尝试别的路径.之前介绍的基础算法中的贪婪算法,动态规划等都具有“无后效性”,也就是在分段处理问题时,某状态一旦确定,将不再改变.而多数问题很难找到"无后效性”的阶段划分和相应决策,而是通过深入搜索尝试和回溯操作完成的. 八皇后问题:8*8的国际象棋棋盘中放八个皇后,是任意两个皇后不能互相吃掉.规则:皇后能吃掉同一行,同一列,同一对角线的任意棋子. 模型建立:不妨设八个

回溯算法之素数环

using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace SeqListSort { /// <summary> /// <ather> /// lihonglin /// </ather> /// <content> /// 把从1到20这20个数摆成一个环,要求相邻的两个数的和是一个素数. ///分析:用回溯算法,考察所有

计科1111-1114班第一次实验作业(NPC问题——回溯算法、聚类分析)

实验课安排 地点: 科技楼423 时间:  计科3-4班---15周周一上午.周二下午 计科1-2班---15周周一下午.周二晚上(晚上时间从18:30-21:10) 请各班学委在实验课前飞信通知大家. 实验内容 (1)八皇后及N皇后问题 八皇后问题,是一个古老而著名的问题,是回溯算法的典型案例.该问题是国际西洋棋棋手马克斯·贝瑟尔于1848年提出:在8X8格的国际象棋上摆放八个皇后,使其不能互相攻击,即随意两个皇后都不能处于同一行.同一列或同一斜线上.问有多少种摆法. 高斯觉得有76种方案.1

DFS ( 深度优先/回溯算法 ) 一

    深度优先搜索算法(英语:Depth-First-Search,简称DFS)是一种用于遍历或搜索树或图的算法. 沿着树的深度遍历树的节点,尽可能深的搜索树的分支.当节点v的所在边都己被探寻过或者在搜寻时结点不满足条件,搜索将回溯到发现节点v的那条边的起始节点.整个进程反复进行直到所有节点都被访问为止.属于盲目搜索,最糟糕的情况算法时间复杂度为O(!n).(Wiki) DFS在搜索过程常常伴随许多优化策略,增加剪枝函数,或者和动态规划结合. 让我们用一道看似简单的例子理解DFS. = = /