关闭

POJ 3009 用DFS搜最短路径 适合用来学习DFS

1247人阅读 评论(0) 收藏 举报

说到最短路径,大部分最会想到BFS,DFS求最短路径还是比较少的,我觉得比如只有一种路径可走的话,可以用DFS。

但是这题比较特殊,因为它的规则不像普通迷宫那么简单。具体就不说了。

DFS求最短路径? 那只能是把所有可能到目的地的方法所需步数都比较一下,保存最小的那个值。

所以,搜到一个解之后不能退出DFS,要继续把余下的压在栈里的递归层跑完(当然,跑的时候又会产生新的递归层压入栈),直到所有的情况都遍历了一遍,才能得出最优解。

所以 DFS 函数应该是void型的。

void dfs(int x,int y,int step)
{
    
    ……
   if(……){
  	map[nx][ny]=0;
   	dfs(ex,ey,step+1);
   	map[nx][ny]=1;
   }
   ……
}

如果找到一个解就退出是这样的:

int dfs(---){
        while(---){
            if(找到解) return 1;
            ……
            if(dfs()) return 1;
            ……
        }
        return 0;
     }

由于有step>10就return 以及 越界就不dfs。所以肯定不存在会死循环的问题。

总结:

对于dfs,不要盲目的套形式,dfs只是一个对于某些数据范围小的问题比较有效的工具,它往往和回溯的思想结合再一起,同事具备遍历全图的能力。拿到题目,如果你意识到这可能是一道dfs题,你首先要明白你需要dfs来完成什么工作,从而确定dfs的形式。

对于递归,就是入栈和出栈的过程,i+1层运行完之后,退回到第i当时进入第i+1层的位置,且此时某些变量还是保持第i层的值。直到第一层运行完(即栈空),函数运行结束。

顺便BB一下:我们知道DFS遍历全图的复杂度基本是N*N,还要递归,找出所有可能的方法,DFS的次数肯定比要遍历全图还高的多。而且N达到了20。所以注意到一点,题目规定了,步数大于10可以直接算失败。想想如果没有这个规定不知道怎么做出来。


详细注释代码:

#include <iostream>
#include <stdio.h>
#include <string.h>
using namespace std;
int map[22][22],m,n,sx,sy;
int dir[][2]={1,0,-1,0,0,1,0,-1};
int ans;
void dfs(int x,int y,int step)
{
    int nx,ny,ex,ey;   //(nx,ny) 代表下一步 (ex,ey) 代表走的这一步
    if(step>10)  return ;  //实际上是剪枝
    for(int i=0;i<4;i++)
    {
        nx=x+dir[i][0];   //下一步
        ny=y+dir[i][1];
        ex=x;
        ey=y;
        while(nx>=0 && nx<m && ny>=0 && ny<n && map[nx][ny]!=1)   //为真代表下一步可走
        {
            ex+=dir[i][0];   //则走这一步
            ey+=dir[i][1];
            if(map[ex][ey]==3) //走的这步是终点吗。
            {
                ans=(step<ans?step:ans);printf("%d\n",step);
                return;
            }
            nx=ex+dir[i][0];  //走完这一步的下一步
            ny=ey+dir[i][1];
            if(nx<0 || nx>=m || ny<0 || ny>=n)
                break;          //如果下一步是越界,说明会直接滑出去,不必再进行dfs
            if(map[nx][ny]==1)  //如果下一步是1,进行深搜.
            {
                map[nx][ny]=0;
                dfs(ex,ey,step+1);
                map[nx][ny]=1;
            }
            //如果下一步还是0,按照题意,当然要继续滑下去,继续while
        }
    }
}
int main()
{
    while(~scanf("%d%d",&n,&m),m||n)
    {
        for(int i=0;i<m;i++)
            for(int j=0;j<n;j++)
            {
                scanf("%d",&map[i][j]);
                if(map[i][j]==2)  {sx=i;sy=j;}
            }
        ans=100000;
        dfs(sx,sy,1);
        if(ans==100000)
            printf("-1\n");
        else
            printf("%d\n",ans);
    }

    return 0;
}


0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:54759次
    • 积分:2063
    • 等级:
    • 排名:第18644名
    • 原创:153篇
    • 转载:4篇
    • 译文:2篇
    • 评论:41条
    个人简介
    前ACMer,现职位算法工程师,主要负责室内定位和SLAM相关算法研究
    最新评论