图的深度优先遍历求最短路径

图的基本知识

图是有N个顶点和M条边组成的集合。
图可以分为有向图和无向图,如果给图的每一条边规定一个方向,那么就称改图为有向图,边称为有向边。
在有向图中,与每一个顶点相关联的边有出边和入边之分,与每一个有向边相关联的两个点也有起点和终点之分。
边没有方向的图称为有向图。

什么是深度优先遍历(DFS)

dfs思想

首先以一个未被访问过的节点作为起始节点u,沿节点u的边走到未被访问的第一个顶点v,然后将顶点v作为新的起始节点;如果当前顶点v没有未被访问的顶点时,则回到上一个顶点u,继续访问u还没有被访问的顶点,重复上述过程,直到所有的顶点都已被访问过为止。
DFS是沿着图的某一分支遍历直到末端,然后回溯,再沿着另一条进行同样的遍历。直到所有的顶点都被访问为止。

举例说明

图以及其邻接矩阵表示如下(book表示是否被访问过):
在这里插入图片描述

dfs遍历具体步骤:
在这里插入图片描述
在这里插入图片描述

代码实现

/*
测试用例:
1 2 2
1 5 10
2 3 3
2 5 7
3 1 4
3 4 4
4 5 5
5 3 3
*/


#include <vector>
#include <iostream>

using namespace std;

class DFS_Traverse
{
private:
    int vertice = 0;//顶点数
    int edge = 0;//边数
    vector<vector<int>> e;
    vector<bool> book;//判断顶点j是否扩展过
    int sum = 0;//统计dfs访问的节点数之和
public:
    DFS_Traverse(int x, int y) :vertice(x), edge(y)
    {
        //图的初始化从下标1开始
        e.resize(vertice + 1);//初始化二维数组的行
        for (int i = 0; i <= vertice; i++)
        {
            e[i].resize(vertice + 1);//初始化二维数组的列
        }
        
        book.resize(vertice + 1);
    }
    //图的初始化
    void Init_tu()
    {
        for (int i = 0; i <= vertice; i++)
        {
            for (int j = 0; j <= vertice; j++)
            {
                if (i == 0 || j == 0)
                {
                    e[i][j] = 0;
                }
                if (i == j)
                {
                    e[i][j] = 0;
                }
                else
                {
                    e[i][j] = INT_MAX;
                }
            }
            book[i] = false;
        }
        book[1] = true;
    }
    //读入图的边,并且根据边的信息初始化数组dis,数组book
    void GetEdgeInfo()
    {
        cout << "输入边的信息(节点1,节点2,权重):" << endl;
        int e1 = 0, e2 = 0, weigth = 0;
        for (int i = 1; i <= edge; i++)
        {
            cin >> e1 >> e2 >> weigth;
            e[e1][e2] = weigth;
            
        }
        
    }

    //打印
    void Print()
    {
        for (int i = 1; i <= vertice; i++)
        {
            for (int j = 1; j <= vertice; j++)
            {
                cout << e[i][j] << "    ";
            }
            cout << endl;
        }
        cout << endl;
    }

    //dfs核心思想
    void dfs_Alg(int current)//current当前所在的节点编号
    {        
        sum++;
        if (sum == vertice)//所有的节点均已被访问
        {
            cout << current << endl;
            return;
        }
        else
        {
            cout << current << " ->";
        }
        for (int k = 1; k <= vertice; k++)
        {
            if (e[current][k] != INT_MAX && current != k && book[k] == 0)
            {
                book[k] = 1;
                dfs_Alg(k);
            }
        }
    }
};

int main()
{
    DFS_Traverse dfs(5, 8);
    dfs.Init_tu();
    dfs.GetEdgeInfo();

    cout << "初始信息:" << endl;
    dfs.Print();
    dfs.dfs_Alg(1);
    
    return 0;
}

在这里插入图片描述

dfs求最短距离

从顶点u开始遍历,找到达节点v的所有路径,取最短距离。

实现(上文所示案例)

#include <vector>
#include <iostream>

using namespace std;

class DFS_Traverse
{
private:
    int vertice = 0;//顶点数
    int edge = 0;//边数
    vector<vector<int>> e;
    vector<bool> book;//判断顶点j是否扩展过
    int sum = 0;//统计dfs访问的节点数之和
    int min = INT_MAX;//最短路径距离
public:
    DFS_Traverse(int x, int y) :vertice(x), edge(y)
    {
        //图的初始化从下标1开始
        e.resize(vertice + 1);//初始化二维数组的行
        for (int i = 0; i <= vertice; i++)
        {
            e[i].resize(vertice + 1);//初始化二维数组的列
        }
        
        book.resize(vertice + 1);
    }
    //图的初始化
    void Init_tu()
    {
        for (int i = 0; i <= vertice; i++)
        {
            for (int j = 0; j <= vertice; j++)
            {
                if (i == 0 || j == 0)
                {
                    e[i][j] = 0;
                }
                if (i == j)
                {
                    e[i][j] = 0;
                }
                else
                {
                    e[i][j] = INT_MAX;
                }
            }
            book[i] = false;
        }
        book[1] = true;
    }
    //读入图的边,并且根据边的信息初始化数组dis,数组book
    void GetEdgeInfo()
    {
        cout << "输入边的信息(节点1,节点2,权重):" << endl;
        int e1 = 0, e2 = 0, weigth = 0;
        for (int i = 1; i <= edge; i++)
        {
            cin >> e1 >> e2 >> weigth;
            e[e1][e2] = weigth;
            
        }
        
    }

    //打印
    void Print()
    {
        for (int i = 1; i <= vertice; i++)
        {
            for (int j = 1; j <= vertice; j++)
            {
                cout << e[i][j] << "    ";
            }
            cout << endl;
        }
        cout << endl;
    }

    //dfs-求最短路径核心思想
    void dfs_minpath_Alg(int current,int distance,int goal)//current是当前节点编号,distance为已经走过的距离
    {
        int j = 0;
        if (distance > min)//如果此次已经走过的距离大于min最短路径,则没有必要继续探索下去
        {
            return;
        }
        if (current == goal)//已经走到目标城市
        {
            if (distance < min)//更新最小值
            {
                min = distance;
            }
            return;
        }
        for (int k = 1; k <= vertice; k++)//将所有节点依次遍历
        {
            //判断当前城市current到城市k是否有路,并判断城市k是否在已经走过的路径中
            if (e[current][k] != INT_MAX && current != k && book[k] == 0)
            {
                book[k] = 1;
                dfs_minpath_Alg(k, distance + e[current][k], goal);//从城市k再出发,继续寻找目标城市
                book[k] = 0;//之前一步探索完毕之后,取消对城市k的标记
            }
        }
        return;
    }
    int Print_minPath()
    {
        return min;
    }
};

int main()
{
    DFS_Traverse dfs(5, 8);
    dfs.Init_tu();
    dfs.GetEdgeInfo();

    cout << "初始信息:" << endl;
    dfs.Print();
    //dfs.dfs_Alg(1);


    cout << "最短路径(顶点1到5顶点):" << endl;
    dfs.dfs_minpath_Alg(1, 0, 5);
    cout << dfs.Print_minPath() << endl;
    return 0;
}

在这里插入图片描述

  • 2
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在迷宫问题中,我们可以使用深度优先搜索算法找到从起点到终点的所有路径,然后再从中选择最短路径。具体步骤如下: 1. 定义一个数组visited来记录每个位置是否被访问过,初始值为0。 2. 定义一个二维数组maze表示迷宫,0表示可以通过,1表示障碍物。 3. 定义一个栈stack,用于存储当前路径。 4. 定义一个整数变量min_dis表示最短路径长度,初始值为正无穷。 5. 定义一个函数dfs(x, y, dis),表示从位置(x, y)开始搜索,当前路径长度为dis。 6. 在dfs函数中,首先判断当前位置是否为终点,如果是,则更新min_dis的值。 7. 然后遍历当前位置的四个方向,如果该方向可以走且未被访问过,则将该位置加入栈中,并将visited数组中该位置的值设为1。 8. 递归调用dfs函数,继续搜索下一步。 9. 搜索完当前位置的所有可达位置后,将该位置从栈中弹出,并将visited数组中该位置的值设为0。 10. 最后返回min_dis的值。 代码如下: ``` int visited[MAX][MAX]; int maze[MAX][MAX]; stack<pair<int, int>> s; int min_dis = INF; void dfs(int x, int y, int dis) { if (x == n && y == m) { min_dis = min(min_dis, dis); return; } visited[x][y] = 1; s.push(make_pair(x, y)); if (x > 1 && maze[x-1][y] == 0 && visited[x-1][y] == 0) { dfs(x-1, y, dis+1); } if (x < n && maze[x+1][y] == 0 && visited[x+1][y] == 0) { dfs(x+1, y, dis+1); } if (y > 1 && maze[x][y-1] == 0 && visited[x][y-1] == 0) { dfs(x, y-1, dis+1); } if (y < m && maze[x][y+1] == 0 && visited[x][y+1] == 0) { dfs(x, y+1, dis+1); } s.pop(); visited[x][y] = 0; } int main() { // 初始化visited和maze数组 dfs(start_x, start_y, 0); cout << min_dis << endl; return 0; } ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值