回溯算法总结

回溯法学习总结

回溯算法也是算法导论中常用的算法,回溯算法类似于暴力求解算法,经常用在求可能解的问题。下面我将从三个方面来介绍回溯算法。
1.回溯法定义
2.回溯算法的解题思路
3.回溯算法例题分析

回溯法定义

1.定义

回溯算法实际上一个类似枚举的搜索尝试过程,主要是在搜索尝试过程中寻找问题的解,当发现已不满足求解条件时,就“回溯”返回,尝试别的路径。回溯法是一种选优搜索法,按选优条件向前搜索,以达到目标。但当探索到某一步时,发现原先选择并不优或达不到目标,就退回一步重新选择,这种走不通就退回再走的技术为回溯法,而满足回溯条件的某个状态的点称为“回溯点”。许多复杂的,规模较大的问题都可以使用回溯法,有“通用解题方法”的美称。
来源于百度百科
下面讲一下我的理解:回溯法思路的简单描述是:把问题的解空间转化成了图或者树的结构表示,然后使用深度优先搜索策略进行遍历,遍历的过程中记录和寻找所有可行解或者最优解。

2.详细解释

回溯法按深度优先策略搜索问题的解空间树。首先从根节点出发搜索解空间树,当算法搜索至解空间树的某一节点时,先利用剪枝函数判断该节点是否可行(即能得到问题的解)。如果不可行,则跳过对该节点为根的子树的搜索,逐层向其祖先节点回溯;否则,进入该子树,继续按深度优先策略搜索。

回溯法的基本行为是搜索,搜索过程使用剪枝函数来为了避免无效的搜索。剪枝函数包括两类:1. 使用约束函数,剪去不满足约束条件的路径;2.使用限界函数,剪去不能得到最优解的路径。

解题步骤

用回溯算法解决问题的一般步骤:
1、 针对所给问题,定义问题的解空间,它至少包含问题的一个(最优)解。
2 、确定易于搜索的解空间结构,使得能用回溯法方便地搜索整个解空间 。
3 、以深度优先的方式搜索解空间,并且在搜索过程中用剪枝函数避免无效搜索。

例题分析

八皇后问题就是:将八位皇后放在一张8x8的棋盘上,使得每位皇后都无法吃掉别的皇后,(即任意两个皇后都不在同一条横线,竖线和斜线上。

public static void findQueen(int i){//寻找皇后节点
    if(i>7){//八皇后的解  
        map++;
        print();//打印八皇后的解
        return;
    }
    
    for(int m=0;m<8;m++){//深度回溯,递归算法
        if(check(i,m)){//检查皇后摆放是否合适
            arry[i][m]=1;
            findQueen(i+1);
            arry[i][m]=0;//清零,以免回溯的时候出现脏数据
            }
    }   
}

我们来重点看一下这段代码:
回溯算法中最重要的就是使用剪枝函数:
1.限界函数

if(i>7){//八皇后的解  
        map++;
        print();//打印八皇后的解
        return;
 }

当 i=8时,说明我们已经找到一种可能解,这是我们就可以退出函数,这就是回溯的边界问题
2.约束函数

public static boolean check(int k,int j){//判断节点是否合适
    for(int i=0;i<8;i++){//检查行列冲突
         if(arry[i][j]==1){
                return false;
         }
    }
    for(int i=k-1,m=j-1; i>=0 && m>=0; i--,m--){//检查左对角线
        if(arry[i][m]==1){
                return false;
        }
    }
    for(int i=k-1,m=j+1; i>=0 && m<=7; i--,m++){//检查右对角线
        if(arry[i][m]==1){
                return false;
        }
    }
    return true;
}

我们使用此函数来约束是否可以存放其他皇后,不满足条件就回溯。

第一次进来,row=0,意思是要在第一行摆皇后,只要传进来的row参数不是8,表明还没出结果,就都不会走if里面的return,那么就进入到for循环里面,column从0开始,即第一列。此时第一行第一列肯定合乎要求(即check方法肯定通过),能放下皇后,因为还没有任何其他皇后来干扰。
关键是check方法通过了之后,在if里面又会调用一下自己(即递归),row加了1,表示摆第二行的皇后了。
第二行的皇后在走for循环的时候,分两种情况,第一种情况:for循环没走到头时就有通过check方法的了,那么这样就顺理成章地往下走再调用一下自己(即再往下递归),row再加1(即摆第三行的皇后了,以此类推)。第二种情况:for循环走到头了都没有通过check方法的,说明第二行根本一个皇后都摆不了,也触发不了递归,下面的第三行等等后面的就更不用提了,此时控制第一行皇后位置的for循环column加1,即第一行的皇后往后移一格,即摆在第一行第二列的位置上,然后再往下走,重复上述逻辑。
注意,一定要添加清零的代码,它只有在皇后摆不下去的时候会执行清0的动作(避免脏数据干扰),如果皇后摆放很顺利的话从头到尾是不会走这个请0的动作的,因为已经提前走if里面的return方法结束了。

最后放上完整代码

public static int[][] arry=new int[8][8];//棋盘,放皇后
public static int map=0;//存储方案结果数量

public static void main(String[] args) {
    // TODO Auto-generated method stub

    System.out.println("八皇后问题");
    findQueen(0);
    System.out.println("八皇后问题共有:"+map+"种可能");
}

public static void findQueen(int i){//寻找皇后节点
    if(i>7){//八皇后的解  
        map++;
        print();//打印八皇后的解
        return;
    }
    
    for(int m=0;m<8;m++){//深度回溯,递归算法
        if(check(i,m)){//检查皇后摆放是否合适
            arry[i][m]=1;
            findQueen(i+1);
            arry[i][m]=0;//清零,以免回溯的时候出现脏数据
            }
    }   
}

public static boolean check(int k,int j){//判断节点是否合适
    for(int i=0;i<8;i++){//检查行列冲突
         if(arry[i][j]==1){
                return false;
         }
    }
    for(int i=k-1,m=j-1; i>=0 && m>=0; i--,m--){//检查左对角线
        if(arry[i][m]==1){
                return false;
        }
    }
    for(int i=k-1,m=j+1; i>=0 && m<=7; i--,m++){//检查右对角线
        if(arry[i][m]==1){
                return false;
        }
    }
    return true;
}

public static void print(){//打印结果
    System.out.print("方案"+map+":"+"\n");
    for(int i=0;i<8;i++){
        for(int m=0;m<8;m++){
            if(arry[i][m]==1){  
                //System.out.print("皇后"+(i+1)+"在第"+i+"行,第"+m+"列\t");
                System.out.print("o ");
            }
            else{
                    System.out.print("+ ");
            }
        }
        System.out.println();
    }
    System.out.println();
}


回溯算法主要还是递归算法,想明白这个过程,我们就可以写一下简单回溯算法。
回溯算法主要有下面几个经典问题,大家平时可以花点时间多研究一下。
(1)装载问题
(2)0-1背包问题
(3)旅行售货员问题
(4)八皇后问题
(5)迷宫问题
(6)图的m着色问题

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,222评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,455评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,720评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,568评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,696评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,879评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,028评论 3 409
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,773评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,220评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,550评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,697评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,360评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,002评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,782评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,010评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,433评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,587评论 2 350

推荐阅读更多精彩内容