深度优先搜索之迷宫解密

  • 前提摘要
    从2000年风靡全球的war3,星际争霸,到现在可能入围奥林匹克奥运比赛项目的LOL。我相信绝大部分的人对这些应该都不陌生,甚至绝大部分的都有接触。不知道大家在体验激情四射的游戏时有没有注意到我们的左下角有一个迷你地图 我们鼠标点在迷你地图的一个坐标上,我们所控制的角色就会自动按照最短的路径去我们所点的目的地。我们不去细想时觉得这是理所当然,但是当我们仔细去注意我们所控制的人物每次都能按照最短的路径去到达终点是不是又会有一点感到很神奇呢?
    这就好比我们的角色身处一个迷宫之中,我们只要点击出口位置一下他们就会自动按照最短最优的路径走出迷宫而且不会发生碰壁。是不是感到很惊讶!没错这就是我们今天需要引出的知识:深度优先搜索

  • 何为深度优先搜索?
    深度优先搜索属于图算法的一种,英文缩写为DFS即Depth First Search.其过程简要来说是对每一个可能的分支路径深入到不能再深入为止,而且每个节点只能访问一次。

    • 举例说明之:下图是一个无向图,如果我们从A点发起深度优先搜索(以下的访问次序并不是唯一的,第二个点既可以是B也可以是C,D),则我们可能得到如下的一个访问过程:A->B->E(没有路了!
      回溯到A)->C->F->H->G->D(没有路,最终回溯到A,A也没有未访问的相邻
      节点,本次搜索结束).简要说明深度优先搜索的特点:每次深度优先搜索的结果必然是图的一个连通分量.深度优先搜索可以从多点发起.如果将每个节点在深度优先搜索过程中的"结束时间"排序(具体做法是创建一个list,然后在每个节点的相邻节点都已被访问的情况下,将该节点加入list结尾,然后逆转整个链表),则我们可以得到所谓的"拓扑排序",即topological sort。
      [

    • 理解深度优先搜索的关键在于当下应该怎么做,至于下一步应该怎么做和前面那一步是相同的

  • 实例

    如果当你不理解某个问题时,用实例来明白我认为是最合适不过了。
    深度优先搜索实例1.png
  • 如果就是给我们一张这样的图片,让我们最快的时间把喊救命的人救出来,你该如何做?

    • 考察点①:如何将现实中的事情模型化
    • 考察点②:如何运用我们所知道的知识将模型支撑起来。

分析:上面的图片由4*5的格子组成 格子中有的地方是不能走。那么我们能不能把图片上的事物以二维数组的形式展现出来。这样我们要在最快的时间内把人救出的问题就可以转变成在如何走最少的格子到达喊救命的人的地方。这样问题就简化成在二维数组构成的图中如何走最少的格子到达目的地。以二维数组表示这个图就是如下这样了。


深度优先搜索实例2.png
  • 这里有几个需要注意的地方
    • 我们走的每一步都是独立的。也就是说我们每一步都有四种可能,我们可以往上下左右四个方向都可以。


      深度优先搜索实例3.png
    • 我们用二维数组的方式去表示图的时候我们要注意下标越界的问题。

    • 控制不走回头路(就是已经走过的路径在这次中不能在走。)

    • 说白了深度优先搜索就是一遍一遍的去尝试,当遇到走不通的时候退回上一步往另外一个方向尝试,如果另外的方向可以走就去另外的方向继续尝试,如果这一步所有的方向都走不通的时候,就在退回的上上步就这样一次一次的循环下去直到到达目的地。(当然这里还要统计走的是不是最短的路径如果不是就还是需要继续尝试下去直到所有的地方都尝试完才结束)

语文水平实在有限~~~,还是上代码详解:

package javasort;
/**迷宫解密之深度优化搜索*/
/*
 *  迷宫解密也可以称为迷宫最短路径路线问题
 *      这也是一个深度优化搜索的案例应用场景 在游戏之中也很常见这种算法比如现在比较活的游戏lol中点击
 *  小地图,我们的角色就会按照那条计算出来的最短路径前进。这其中就涉及到深度优化搜索的身影。
 *      一般我们采用这种方法,我们都应该事先建立一个与之相对应的模型,如果是图,我们可以建立一个
 *  类似于二维数组一样的模型与之对应。
 *     现在我们需要解决的问题是如果一个人在一个点去另外一个点的最短路径的问题 并计算出最短路径
 *  我们定义的模型如下:采用二维数组
 *  {[0,0,1,0],
 *  [0,0,0,0],
 *  [0,0,1,0],
 *  [0,1,0,0],
 *  [0,0,0,1]}
 *  其中0代表可以走的地方 1代表不能走的地方
 *  (x,y) x代表行 y代表列
 *  (0,0)坐标是我们的起点
 *  (3,2) 代表目的地  
 *  求出到达目的地的最短路径(注意一次只能走一步 上下左右 但是不能越界)    
 * */
public class MazeDecode {
    // 定义一个参照数组 相当于记录所走的地方
    private static int[][] book = new int[5][4];
    // 定义地图 初始化地图
    private static int[][] a = {{0,0,1,0},
                                {0,0,0,0},
                                {0,0,1,0},
                                {0,1,0,0},
                                {0,0,0,1}};
    // 定义四个方向 上下左右 上=x-1,y不变 下=x+1,y不变 左=x不变,y-1 右=x不变,y+1
    // 根据这个特性我们可以将这四个方向定义成一个二维数组
    private static int[][] direction = {{-1,0},{1,0},{0,1},{0,-1}};
    // 定义一个走的步数
    private static int stepSum = 9999;
    /**这是每一次走的函数*/
    //x y 相等于 行和列 因为数组是从0开始的所以xy也是从0开始
    public static void dfs(int tx, int ty,int step){
        //System.out.println(tx +":"+ty+":"+step);
    // x,y 这里表示xy点已经被走过了所以需要标记
    //  book[tx][ty] = 1;
    // 如果到达了目的地就需要return
        if(tx==3 && ty==2){
    // 表示到达目的地 这里还需要记录所走的步数
            if(step < stepSum){
                stepSum = step;
            }
    // 将所走的路径遍历出来 也就是book二维数组中等于1的
            for(int m=0;m<5;m++){
                for(int n=0;n<4;n++){
                    if(book[m][n] == 1){
                        System.out.print("("+m+","+n+")");
                    }
                }
            }
            System.out.print("步数是:"+step);
            System.out.println();
            return;
        }   
    // 因为每一步都有四种走法
        for(int i=0;i<direction.length;i++){
            int x = tx+direction[i][0];
            int y = ty+direction[i][1];
            //需要判断xy有没有越界以及xy的点是不是可以走的点
            if(x>=0 && x<5 && y>=0 && y <4 && a[x][y] == 0 && book[x][y] == 0){
                book[x][y] = 1;
                dfs(x,y,step+1);
                //step--;
                // 这一步很重要 相当于走了一趟之后重新走的时候撤掉标记
                book[x][y] = 0;
            }
        }
        //return;
    }
    public static void main(String[] args) {
        book[0][0]=1;
        dfs(0,0,0);
    }

}

总结

  • 所谓深度优先搜索的核心思想是:解决当下该如何做,至于后面的和前一步是一样的 只是无聊的递归下去。
  • 把握越界的几个零界点。(横轴方向,竖轴方向,到达目的地点)
  • 事先定义一个和数组一样大的一个空数组,用来记录经过了那些点(标记)。这样做的目的是不走已经走过的点。
  • 如果是返回上一步的时候,要将标记取消这一步是这里代码的精华之处。为什么要取消标记?因为如果前面的尝试已经结束了 返回上一步,如果不把标记取消那么后面就没法继续尝试。()
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,189评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,577评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,857评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,703评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,705评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,620评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,995评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,656评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,898评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,639评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,720评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,395评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,982评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,953评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,195评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,907评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,472评论 2 342

推荐阅读更多精彩内容