数据结构 图 (Part II) 最短路算法

1. Dijkstra (朴素)

  是用来求单源最短路的:求一个点到其他点的最短路

 ps:(什么堆优化我不会,也懒得学了)

 适合所有边权都是“正数”的情况,时间复杂度为O(n^2)

首先初始化:dist[i] = +∞, dist[st]=0 (st为起始点)

然后for循环n次:① 找出目前没有选中的点中距离最短的点,选其为当前点now

                            ② 再用now来更新其他点的最短路距离(dist[i])

路径更新: 

用二维vector比较方便,vector<int> path[MAXN];  用二维数组我反而不会写

初始化:path[st].push_back(st);  //只初始化起点就ok

用now来更新其余点时,可以理解为该点是从now点过来的,所以:

              path[j]=path[now];      // 二维数组能这样直接赋值吗?!不能,所以vector yyds啊!

              path[j].push_back(j);  // 再把自己放进去

代码如下,其中arr为邻接矩阵,可以看出时间复杂度为O(n^2)

void Dij(int st) {
	memset(dis, 0x3f3f3f3f, sizeof(dis));
	memset(walked, 0, sizeof(walked));
	dis[st] = 0;
	path[st].push_back(st); 
	for (int i = 0; i < n; i++) {
		int now = n;   //因为dis[n]为无穷大,因此now会在下面的循环被更新
		for (int j = 0; j < n; j++) {
			if (dis[now] > dis[j] && !walked[j])
				now = j;
		}
//		if(dis[now]==0x3f3f3f3f) return;
		walked[now] = 1;
		for (int j = 0; j < n; j++) {
			if (!walked[j] && dis[j] > dis[now] + arr[now][j]) {  //只用更新没被走过的点
				dis[j] = dis[now] + arr[now][j];
				path[j] = path[now];
				path[j].push_back(j);
			}
		}
	}
}

ps:当初自己学的时候快被折磨坏了,然后一遍遍的模拟代码执行的过程,终于懂了o(╥﹏╥)o,想想那段时光还真是痛苦

2. Floyd弗洛伊德

多源最短路:求任意两个点的最短路径

边权可正可负,但是不能出现负环!

首先初始化 dis[ i ][ j ] = +∞

然后基于动态规划的思想,看看从i到j能不能被 从i到k 加上 从k到j 代替 (即更短的路)

路径更新:

int path[MAXN][MAXN];

初始化 path[ i ][ j ] = j

如果能被更新,则有path[ i ][ j ] = k ,其含义是从i到j需要经过点k,此时再去找path[ k ][ j ],如果path[ k ][ j ] == j,则说明到达终点,否则一直找下去。

代码如下,时间复杂度为O(n^3) 

void Floyd() {
	for(int i=1; i<=n; i++)
		for(int j=1; j<=n; j++) path[i][j]=j; //初始化中转站
	for(int k=1; k<=n; k++)
		for(int i=1; i<=n; i++)
			for(int j=1; j<=n; j++) {
				//if(dis[i][k]==MAX||dis[k][j]==MAX) continue;
				if(dis[i][j]>dis[i][k]+dis[k][j]) {
					dis[i][j]=dis[i][k]+dis[k][j];
					path[i][j]=path[i][k];    //path[i][j]=k也可以
				}
			}
	for(int i=1; i<=n; i++) { //从k到i,i为终点
		int k=st;  //st为起点
		if(st==i) continue; 
		cout<<dis[st][i]<<endl;  //输出从st到i的最短路的权值 
		while(k!=i) {
			cout<<k<<"--";//输出路径
			k=path[k][i];
		}
		cout<<i<<endl;
	}
}

最后dis[i][j]就是从i到j的最短路径长度,因此用Floyd也可以判断出是否成环,只要从顶点i到顶点i(到他自己),即dis[i][i]≠一开始的+∞,那么就存在环。

ps:多么的!简单明了啊(除了path)!!就三个for,背都背过了,对初学者多么友好啊,总之我当时学的时候很喜欢,然后被一堆人说:时间复杂度太高啦,大一点的数据就跑不了了。我:学校oj能过就行,我管这些= =

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值