算法九——回溯算法

文章出处:极客时间《数据结构和算法之美》-作者:王争。该系列文章是本人的学习笔记。

理解回溯

在我们的一生中,会遇到很多重要的岔路口。在岔路口上,每个选择都会影响我们今后的人生。有的人在每个岔路口都能做出最正确的选择,最后生活、事业都达到了一个很高的高度;而有的人一路选错,最后碌碌无为。如果人生可以量化,那如何才能在岔路口做出最正确的选择,让自己的人生“最优”呢?

我们可以借助前面学过的贪心算法,在每次面对岔路口的时候,都做出看起来最优的选择,期望这一组选择可以使得我们的人生达到“最优”。但是,我们前面也讲过,贪心算法并不一定能得到最优解。那有没有什么办法能得到最优解呢?

2004 年上映了一部非常著名的电影《蝴蝶效应》,讲的就是主人公为了达到自己的目标,一直通过回溯的方法,回到童年,在关键的岔路口,重新做选择。当然,这只是科幻电影,我们的人生是无法倒退的,但是这其中蕴含的思想其实就是回溯算法。

回溯的处理思想,有点类似枚举搜索,又被称为“暴力搜索”。我们枚举所有的解,找到满足期望的解。为了有规律地枚举所有可能的解,避免遗漏和重复,我们把问题求解的过程分为多个阶段。每个阶段,我们都会面对一个岔路口,我们先随意选一条路走,当发现这条路走不通的时候(不符合期望的解),就回退到上一个岔路口,另选一种走法继续走。

八皇后问题

在一个8x8的棋盘中,八个棋子(皇后)不能在同一行,同一列,对角线上相遇。第一幅图是满足要求的,第二幅图是不满足要求的。求八皇后所有的摆放方式。

我们把这个问题分成8个阶段。依次将八个棋子放到第一行、第二行…。在放置过程中不停地检查看当前位置是否满足条件。如果不满足就换另一种方式试。

public class EightQueens {
    public static void main(String[] args){
        new EightQueens().eightQueens();
    }

    public void eightQueens(){
        cal8queens(0);
    }
    private int[] result = new int[8];//下标表示第几行,值表示皇后在第几列
    private void cal8queens(int row) {
        if(row==8){
            printResult();
        }else{
            for(int j=0;j<8;j++){
                if(isOk(row,j)){
                    result[row] = j;
                    cal8queens(row+1);
                }
            }
        }
    }

    private boolean isOk(int row, int col) {
        //不在同一列
        int leftUp = col-1,rightUp=col+1;
        for(int i=row-1;i>=0;i--){
            if(i!=row && result[i]==col) return false;
            if(leftUp>=0 && result[i]==leftUp) return false;
            if(rightUp<8 && result[i]==rightUp) return false;
            leftUp++;
            rightUp--;
        }
        return true;
    }

    private void printResult() {
        for(int i=0;i<result.length;i++){
            System.out.println();
            for(int j=0;j<8;j++){
                if(j==result[i]){
                    System.out.print("Q");
                }else{
                    System.out.print("*");
                }
                System.out.print(" ");
            }
        }
        System.out.println();
    }
}

回溯法还可以适于练习的题目:0-1背包问题、正则表达式问题 。

发布了148 篇原创文章 · 获赞 35 · 访问量 10万+

猜你喜欢

转载自blog.csdn.net/flying_all/article/details/100029799