算法思路
比如有下面的一个无向图,我们需要求顶点1到其他各个顶点的最短路径。
首先我们需要维护一个dist
数组和tag
数组,dist[i]
表示顶点i
到起点目前的最短路径,tag[i]
表示顶点i
是否已经被标记过。*只要tag[i] = true
,那么dist[i]
就是顶点i到起点的最短路径
由于起点是1,所以dist[1]
的值为0
顶点1与3 5 6相连,把距离写入dist:
扫描dist数组,发现目前未被标记过的顶点中,3的最短路径最小,所以把当前顶点从1变为3,并标记顶点3。
与3相连的且未被标记过的顶点有2 4,路径长度分别为10+5 10+50,写入dist数组:
再次扫描dist数组,目前只有顶点2的最短路径最小:
扫描dist数组,发现目前未被标记过的顶点中,5的最短路径最小。
与5相邻的且未被标记过的顶点中,4的路径为30+20=50,6的路径为30+60=90,均比当前dist数组里的值小,所以再次更新dist数组:
重复上面的步骤:
所以,从顶点1开始,到顶点2,3,4,5,6的最短路径分别为15 10 50 30 60
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define INF 0x3f3f3f3f //无穷大
#define MAXN 1024 //最大顶点个数
int mat[MAXN][MAXN]; //邻接矩阵
int dist[MAXN]; //存储顶点i到起点的当前最短路径
bool tag[MAXN]; //用于标记顶点i有没有被访问过(确定dist[i]是不是已经是最小距离)
int n; //顶点的个数
int m; //边的个数
/*
初始化
*/
void init(){
memset(dist,INF,sizeof(dist));
memset(tag,0,sizeof(tag));
for(int i = 0;i<MAXN;++i){
for(int j = 0;j<MAXN;++j){
mat[i][j] = -1;
}
}
}
void dijkstra(int x){
dist[x] = 0; //自己到自己的最短路径是0
tag[x] = 1; //当前顶点已被访问
int v = x; //当前的顶点
//因为要把所有顶点都标记上,一共n个顶点
//所以需要循环n次才能标记完全部
for(int i = 0;i < n;++i){
for(int j = 1;j<=n;++j){
if(mat[v][j] != -1){
//表示有v到i的边存在
dist[j] = min(dist[v] + mat[v][j],dist[j]); //记录节点i的当前最小距离
}
}
int mi = INF; //最短路径
for(int j = 1;j<=n;++j){
if(!tag[j] && dist[j] < mi){
mi = dist[j];
v = j;
}
}
tag[v] = 1; //标记当前节点已被访问
}
}
int main() {
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
init();
cin >> n >> m;
int a,b,c; //a b是边连接的两个点 c是权值
for(int i = 0;i<m;++i){
cin >> a >> b >> c;
mat[a][b] = c;
mat[b][a] = c;
}
int x; //起始点
cin >> x;
dijkstra(x);
//输出x到顶点i的最短路径
for(int i = 1;i<=n;++i){
cout << i << " " << dist[i] << endl;
}
return 0;
}