3),迪杰斯特拉算法(解决单源最短路径)
基本思想:每次找到离源点(如1号结点)最近的一个顶点,然后以该顶点为中心进行扩展,最终得到源点到其余所有点的最短路径。
基本步骤:1,设置标记数组book[]:将所有的顶点分为两部分,已知最短路径的顶点集合P和未知最短路径的顶点集合Q,很显然最开始集合P只有源点一个顶点。book[i]为1表示在集合P中;
2,设置最短路径数组dst[]并不断更新:初始状态下,令dst[i] = edge[s]i,很显然此时dst[s]=0,book[s]=1。此时,在集合Q中可选择一个离源点s最近的顶点u加入到P中。并依据以u为新的中心点,对每一条边进行松弛操作(松弛是指由结点s–>j的途中可以经过点u,并令dst[j]=min{dst[j], dst[u]+edge[u][j]}),并令book[u]=1;
3,在集合Q中再次选择一个离源点s最近的顶点v加入到P中。并依据v为新的中心点,对每一条边进行松弛操作(即dst[j]=min{dst[j], dst[v]+edge[v][j]}),并令book[v]=1;
4,重复3,直至集合Q为空。
例1:给你n个点,m条无向边,每条边都有长度d和花费p,给你起点s,终点t,要求输出起点到终点的最短距离及其花费,如果最短距离有多条路线,则输出花费最少的。
输入:输入n,m,点的编号是1~n,然后是m行,每行4个数 a,b,d,p,表示a和b之间有一条边,且其长度为d,花费为p。最后一行是两个数s,t;起点s,终点 t。n和m为 0 时输入结束。(1<n<=1000, 0<m<100000, s != t)
输出:输出一行,有两个数, 最短距离及其花费。
分析:由于每条边有长度d和花费p,最好构建边结构体存放,此外可以使用邻接链表,使用邻接链表时需要将上面的核心代码修改几个地方:
1,初始化dst[]时使用结点1的邻接链表;
2,更新最短路径数组时,k的范围由1n变为1edge[u].size()。先采用邻接矩阵解决此题,再使用邻接表解决此题,两种方法的思路都一样:初始化邻接矩阵或邻接链表,并
初始化最短路径数组dst ----> n-1轮边的松弛中,先找到离新源点最近的中心点u,之后根据中心点u为转折点来更新路径数组。
使用邻接矩阵求解:
//***对于无向图,输入n,m,点的编号是1~n,然后是m行,每行4个数 a,b,d,p,表示a和b之间有一条边,且其长度为d,花费为p。最后一行是两个数s,t;起点s,终点 t。***/
//***n和m为 0 时输入结束。(1<n<=1000, 0<m<100000, s != t) 输出:输出一行,有两个数, 最短距离及其花费。***/
#include<bits/stdc++.h>
using namespace std;
#define nmax 1001
#define inf 99999999
struct Edge{
int len;//边长
int cost;//权重
};
Edge edge[nmax][nmax];//邻接矩阵
int dst[nmax];//最短路径数组
int spend[nmax];//最小花费数组
int book[nmax];//标记走过的数组
int n, m, stNode, enNode;
int main(){
while(cin >> n >> m && n != 0 && m != 0){
int a, b, i, j;
//构建邻接矩阵和最短路径数组
//初始化
for(i = 1; i <= n; i++){
for(j = 1; j <= n; j++){
edge[i][j].cost = 0;
edge[i][j].len = inf;
}
edge[i][i].len = 0;
}
while(m--){//初始化
cin >> a >> b;
cin >> edge[a][b].len >> edge[a][b].cost;
edge[b][a].len = edge[a][b].len;
edge[b][a].cost = edge[a][b].cost;
}
cin >> stNode >> enNode;//开始的点和结束的点
//初始化数组
for(i = 1; i <= n; i++){
dst[i] = edge[stNode][i].len;
spend[i] = edge[stNode][i].cost;
}
memset(book, 0, sizeof(book));
book[stNode] = 1;
//开始迪杰斯特拉算法,进行剩余n-1次松弛
int k;
for(k = 1; k <= n-1; k++){
//找离源点最近的顶点u
int minNode, min = inf;
for(i = 1; i <= n; i++){
if(book[i] == 0 && min > dst[i] /* || min == dst[i]&& edge[stNode][min].cost > edge[stNode][i].cost*/){
min = dst[i];
minNode = i;
}
}
book[minNode] = 1;//易错点1,错写成book[i]=1
//以中心点u为转折点来更新路径数组和花费数组
for(i = 1; i <= n; i++){
if(book[i] == 0 && dst[i] > dst[minNode] + edge[minNode][i].len || dst[i] == dst[minNode] + edge[minNode][i].len && spend[i] > spend[minNode] + edge[minNode][i].cost){
dst[i] = dst[minNode] + edge[minNode][i].len;//易错点2,错写成dst[i]+
spend[i] = spend[minNode] + edge[minNode][i].cost;
}
}
}
cout << dst[enNode] << setw(3) << spend[enNode] << endl;
}
return 0;
}
转载