图的深度优先遍历求最短路径
图的基本知识
图是有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;
}