图论:(重要知识点)
图的存储和表达式:邻接矩阵和邻接链表
图的遍历:深度优先,广度优先
拓扑排序
最短路径: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)
参考代码:
//该程序描述的是无向有权图
#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");
}
}