DFS新手入门(第十届蓝桥杯E题)
前言
人生第一篇博客,尝试写博客是因为发现需要在考研路上给自己一些激励,同时也是为了能够记载一些计算机相关的知识,希望能够在考研路上对自己有所帮助。
背景
第十届蓝桥杯Java B组随缘得了省一,在考场上看到E题迷宫就知道因该用DFS就能解,但奈何于平时眼高手低,想了半天也没能写出来,同时也说明自己算法的基础功很差,这使我只能从简单入手,重新学习DFS。
官方题目
下图给出了一个迷宫的平面图,其中标记为1 的为障碍,标记为0 的为可以通行的地方。
010000
000100
001001
110000
迷宫的入口为左上角,出口为右下角,在迷宫中,只能从一个位置走到这个它的上、下、左、右四个方向之一。
对于上面的迷宫,从入口开始,可以按DRRURRDDDR 的顺序通过迷宫,一共10 步。其中D、U、L、R 分别表示向下、向上、向左、向右走。对于下面这个更复杂的迷宫(30 行50 列),请找出一种通过迷宫的方式,其使用的步数最少,在步数最少的前提下,请找出字典序最小的一个作为答案。请注意在字典序中D<L<R<U。
入门DFS
先对DFS进行通俗的介绍。DFS即深度优先搜索,即在对图进行搜索的过程中以向深层访问为优先的对图访问的一种方式。DFS的中需要注意的是要开辟一个与原图大小相等的储存访问情况的矩阵,来对访问情况进行标记,这样能够避免重复访问,能够大幅度的降低时间复杂度。
先简化一下官方的题目,即计算从左上角的起始地点达到右下角的终点的最短路径的长度,而不去显示其具体路径,这样就把官方题目简化成了标准的DFS问题。
第一步终止判断
void dfs(int x,int y,int step)
{
if(x==q-1 && y==p-1)
{
if(step<minstep)
minstep = step;
return;
}
return;
}
程序的目的的是找到终点,因此参数中应当有当前位置(x,y),其次由于要计算其最短路径,因此应当包含参数step表示步数。其中p,q是图矩阵的行列,达到终止条件后,还应当对最短路径minstep进行刷新。要注意的是终止后的return,以防无法返回上一层。
第二步深搜
int next[][] ={
{0,1},
{1,0},
{0,-1},
{-1,0},};
for(k = 0;k<4;k++)
{
tx = x + next[k][0];
ty = y + next[k][1];
if(tx<0||ty<0||tx>=q||ty>=p)
{
continue;
}
if(migong[tx][ty]==0&&flag[tx][ty]==0) //flag[x][y] == 1 表示访问过该节点
{
flag[tx][ty] = 1;
dfs(tx,ty,step+1);
flag [tx][ty] = 0;
}
}
这部分是DFS的核心代码。其中next二维矩阵储存方向,即按照右,下,左,上的顺时针顺序。之后对四个方向进行遍历,在对越界进行处理之后,应判断下一节点是否访问过,是否是障碍物。若既没有访问过,且不是障碍,则将此节点标记为已访问,并对此节点进行深搜。在跳出之后应当对此节点的标记重新设为未访问,以避免之后其他节点进行搜索时无法访问。
完整代码
package dfs;
public class Dfs {
int p=6,q=4;
int minstep=1000000;
static int[][] migong ={{0,1,0,0,0,0},
{0,0,0,2,0,0},
{0,0,3,0,0,4},
{5,6,0,0,0,0}};
static int flag[][] = new int[migong.length][migong[0].length];
void dfs(int x,int y,int step)
{
int k =0;
int tx,ty;
if(x==q-1 && y==p-1)
{
if(step<minstep)
minstep = step;
return;
}
int next[][] ={
{0,1},
{1,0},
{0,-1},
{-1,0},};
for(k = 0;k<4;k++)
{
tx = x + next[k][0];
ty = y + next[k][1];
if(tx<0||ty<0||tx>=q||ty>=p)
{
continue;
}
if(migong[tx][ty]==0&&flag[tx][ty]==0) //flag[x][y] == 1 表示访问过该节点
{
flag[tx][ty] = 1;
dfs(tx,ty,step+1);
flag [tx][ty] = 0;
}
}
return;
}
public static void main(String []args)
{
Dfs dd = new Dfs();
flag[0][0] = 1;
dd.dfs(0,0,0);
System.out.println(dd.minstep);
}
}
总结
DFS本身其实不难理解,代码量也不大,但是比赛时候却完全写不出来,说明确实是本人眼高手低,代码功底太过薄弱,需要改正。