图论:Dijkstra算法及Floyd算法

图论:(重要知识点)

图的存储和表达式:邻接矩阵和邻接链表

图的遍历:深度优先,广度优先

拓扑排序

最短路径:Dijkstra算法及Floyd算法

对大神博客进行了借鉴:https://blog.csdn.net/qq_34989804/article/details/82149495

Dijkstra算法:(广度优先遍历)

        单源点的最短路径问题:给定带权有向图G和源点v,求从v到G中其余各顶点的最短路径。

        下面我们来看看下面的表,看看计算的过程。假设从A点出发,有三个量需要表示:1.每个点离A点的最短路径长度(dist[]);2.其他点是否走过(visit[]);3.每个点到A点的最短路径(path[])。1.首先初始化邻接矩阵,2.然后找到dist中离A点最近的点,记录其距离值及下标,3.更新dist数组(要判断两点之间是否有链接),再找离当前点最近的点重复上面2,3步骤。

步骤写的有点粗糙:(推荐小姐姐讲解https://www.bilibili.com/video/BV1bQ4y1A74i?from=search&seid=13151513925105551094)

参考代码:

扫描二维码关注公众号,回复: 11493507 查看本文章
//该程序描述的是无向有权图
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>

using namespace std;
int matrix[100][100];//邻接矩阵
bool visited[100];//标记数组
int dist[100];//原点到i顶点的最短距离
int pre[100];//记录最短路径。pre[i]放的是i的前驱节点
int source;//源节点
int vertex_num;//顶点数
int edge_num;//边数

void Dijkstra(int source)
{
	//首先初始化
	memset(visited, 0, sizeof(visited));
	visited[source] = true;//源节点为true,从源节点开始走
	for (int i = 0; i < vertex_num; i++)
	{
		dist[i] = matrix[source][i];
		pre[i] = source;
	}

	int min_cost;//最短距离
	int min_cost_index;//权值最小的那个顶点的下标。(求好了)
	//主循环,(要走n个顶点,循环n-1次,因为源节点不需要走了)
	for (int i = 1; i < vertex_num; i++)
	{
		min_cost = INT_MAX;
		for (int j = 0; j < vertex_num; j++)
		{
			//注意要确保这个点没有找过。(找最小的点及对应的下标)
			if (visited[j] == false && dist[j] < min_cost)
			{
				min_cost_index = j;
				min_cost = dist[j];
			}
		}

		visited[min_cost_index] = true;//找到某一个点的最短距离
		//利用该点进行dist的更新,并且调整前驱。
		for (int j = 0; j < vertex_num; j++)
		{
			//确保有连接
			if (visited[j] == false && matrix[min_cost_index][j] != INT_MAX&&min_cost + matrix[min_cost_index][j] < dist[j])
			{
				dist[j] = min_cost + matrix[min_cost_index][j];//更新源节点到当前节点的最小路径权值
				pre[j] = min_cost_index;//保存最短路径
			}
		}
	}
}

int main()
{
    cout << "请输入图的顶点数(<100):";
	cin >> vertex_num;
	cout << "请输出图的边数: ";
	cin >> edge_num;
	for (int i = 0; i < vertex_num; i++) //中间的对称线设置为0,其余初始化为INT_MAX(无穷大)
	{
		for (int j = 0; j < vertex_num; j++)
		{
			matrix[i][j] = (i != j) ? INT_MAX : 0;
		}
	}
	cout << "请输入边的信息:\n";
	int u, v, w;
	for (int i = 0; i < edge_num; i++)
	{
		cin >> u >> v >> w;
		matrix[u][v] = matrix[v][u] = w; //构建邻接矩阵
	}

	cout << "请输入源点(<" << vertex_num << "): ";
	cin >> source;
	Dijkstra(source);
	for (int i = 0; i < vertex_num; i++)
	{
		if (i != source)
		{
			//路径是反的,从目标点向前不断找前驱的过程。
			cout << source << "到" << i << "最短距离: " << dist[i] << ",路径是:" << i;
			int t = pre[i];
			while (t != source) 
			{
				cout << "--" << t;
				t = pre[t];
			}
			cout << "--" << source << endl;
		}
	}

	system("pause");
	return 0;
}

Floyd算法

      多源点的最短路径问题:每个点到其他各个点的最短路径。该算法的时间复杂度为O(n^3),该算法的基本思路是先列出邻接矩阵,求出每个点到其他点的距离,并用无穷大INF表示两个点之间没有连接。然后将每两个节点之间插入所有节点,求出最短路径。灵魂表达式if (e[i][j]>e[i][k] + e[k][j])   e[i][j] = e[i][k] + e[k][j]; 该表达式所表达的意思是(举个栗子):A->B,B->C,A到C的距离大于A到B加上B到C的距离就更新为最小值。

推荐B站视频:https://www.bilibili.com/video/BV1Ut41197NX?from=search&seid=5385609856867228609

参考代码:

//Floyd算法,该程序描述的是有权网
void Floyd()
{
	//e[10][10]表示邻接矩阵,n为顶点个数,m为边的个数
	int e[10][10], n, m, t1, t2, t3;
	int inf = 99999999; //用inf(infinity的缩写)存储一个我们认为的正无穷值
	//读入n和m,n表示顶点个数,m表示边的条数
	scanf("%d %d", &n, &m);

	//初始化(初始化邻接矩阵)
	for (int i = 1; i <= n; i++)
		for (int j = 1; j <= n; j++)
			if (i == j) e[i][j] = 0;
			else e[i][j] = inf;
			//读入边
			for (int i = 1; i <= m; i++)
			{
				scanf("%d %d %d", &t1, &t2, &t3);
				e[t1][t2] = t3;
			}

			//Floyd-Warshall算法核心语句
			for (int k = 1; k <= n; k++)
				for (int i = 1; i <= n; i++)
					for (int j = 1; j <= n; j++)
						if (e[i][j]>e[i][k] + e[k][j])
							e[i][j] = e[i][k] + e[k][j];

			//输出最终的结果
			for (int i = 1; i <= n; i++)
			{
				for (int j = 1; j <= n; j++)
				{
					printf("%10d", e[i][j]);
				}
				printf("\n");
			}
}

猜你喜欢

转载自blog.csdn.net/L_smartworld/article/details/107504915
今日推荐