求最短路径-----迪杰斯特拉算法

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;
}


转载
在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值