深度优先搜索最优性剪枝

深度优先搜索最优性剪枝,第1张

对于求最优解的一类问题,通常可以用可行性剪枝,比如再求解迷宫最短路的时候,如果发现当前的步数已经超过了当前的最优解,那么当前状态开始的搜索都是多余的,因为这样搜索下去永远都不可能搜到更优解。通过这样的剪枝,可以省去大量多余的计算。
此外,在搜索是否有可行解的过程中,一旦找到了一组可行解,后面的搜索都不必再进行了,这算是最优性剪枝的一个特例。

有一个 n×m 大小的迷宫。其中字符’S’表示起点,字符’T’表示终点,字符’*‘表示墙壁,字符’.‘表示平地。你需要从’S’出发走到’T’,每次只能向上下左右相邻的位置移动,并且不能走出地图,也不能走进墙壁。保证迷宫至少存在一种可行的路径,输出’S’走到’T’的最少步数。

这道题我们通常会用BFS解决这个问题,搜索到的第一个结果就是答案。现在我们考虑用DFS来解决这个问题,第一个搜到的答案ans不一定就是正解,但是正解一定小于等于ans。于是,如果当然步数大于等于ans就直接剪枝,并且每找到一个可行的答案,都会更新ans。

首先定义一些全局变量,n、m为迷宫的行数和列数,maze记录迷宫各个位置是否可以走,vis记录DFS过程中当前位置是否被访问过,dir表示每次枚举的四个方向,ans记录当前到达重点的最小步数,初始值为一个在题目中相当于无限大的数。
in函数用于判断每次扩展的位置是否在迷宫中。
dfs一共有3个参数,x、y表示当前位置的坐标,step表示当前的步数。分别在函数的入口处和出口处更新当前位置是否访问,然后枚举四个方向,如果(tx,ty)满足在边界内、不是墙、没有访问过,就继续扩展,并且步数增加1。
如果当前步数大于等于ans就剪枝,因为继续搜下去不可能更优了。如果当前位置为终点,就更新ans并返回。

示例代码:

#include 
#include 
#include 
using namespace std;
int n,m;
string maze[110];
bool vis[110][110];
int dir[4][2]={{-1,0},{0,-1},{1,0},{0,1}};
int ans=100000;
bool in(int x,int y){
    return 0<=x && x<n && 0<=y && y<m;
}
void dfs(int x,int y,int step){
    if(step>=ans){
        return;
    }
    if(maze[x][y]=='T'){
        ans=step;
        return;
    }
    vis[x][y]=1;
    for(int i=0;i<4;i++){
        int tx=x+dir[i][0];
        int ty=y+dir[i][1];
        if(in(tx,ty) && maze[tx][ty]!='*' && !vis[tx][ty]){
            dfs(tx,ty,step+1);
        }
    }
    vis[x][y]=0;
}
int main() {
    cin>>n>>m;
    for(int i=0;i<n;i++){
        cin>>maze[i];
    }
    int x,y;
    for(int i=0;i<n;i++){
        for(int j=0;j<m;j++){
            if(maze[i][j]=='S'){
                x=i,y=j;
            }
        }
    }
    dfs(x,y,0);
    cout<<ans<<endl;
    return 0;
}

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/langs/1295827.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-06-10
下一篇 2022-06-10

发表评论

登录后才能评论

评论列表(0条)

保存