最短路径总结

1. Floyd

思想:

尝试将每个点添加到两点间, 看距离是否变短, 变短则更新

输入: 图矩阵

输出: 每个点到每个点的最短距离

核心代码:

for(k = 1; k <= n; k++)
    for(j = 1; j <= n; j++)
        for(i = 1; i <= n; i++)
            if(e[i][j] > e[i][k] + e[k][j])
                e[i][j] = e[i][k] + e[k][j]  //松弛操作

2. Dijkstra(单源点最短路径)

思想

找到未知的离源点最短距离的点 , 尝试将该点加入到两点之间, 看距离是否变短

这里将 Floyd 的每个点改成了 离源点最短距离的点

  • 这里因为每次都只考虑未知的点, 所以当有负权边出现, 而在此之前已经确定了某几个点时, 有可能经过负权边之后, 以前确定的最短距离会更短, 所以不可解决负权边.

输入: 矩阵图

输出: 源点到每个点的最短路径

数据结构:

dis: 存储该点到其他点的最短距离

e : 无向图

算法

循环 n 次以下步骤:

  1. 找到 dis 未访问过且最短距离的点: u u u

  2. 是否找到该点:

    ​ 否: 退出循环

  3. 将该点状态置为已访问过, 标记为已知最短距离 visit[u] = true

  4. 尝试把该点 v v v 添加到两个点(u 与 源点)的路径之间 e v , u + d i s u e_{v,u} + dis_u ev,u+disu

    1. 添加后距离是否减小 d i s v &gt; e v , u + d i s u dis_v &gt; e_{v,u} + dis_u disv>ev,u+disu

      ​ 是: 添加

      ​ 否:不添加

核心代码

for (int i = 0; i < n; i++){
    int u = -1; min = inf;
    for(int j = 0; j < n; j++){
        if(visite[j] == false && dis[j] < min){
            min = dis[j];
            u = j;
        }
    }
    if(u == -1) break;
    visit[u] = true;
    
    for(int v = 0; v < n; v++){
        if(visit[v] == false && e[u][v] != inf){
            // next,your code depends on needs
            if(dis[v] > e[u][v] + dis[u]){ //松弛操作
                dis[v] = e[u][v] + dis[u];
            }
        }
    }
}

3. Bellman-Ford(单源点最短路径, 不受负权边影响)

思想

执行 n-1次以下操作: 遍历所有的边, 尝试把每一条边添加到两点之间

  • 因为每次都会考虑所有边, 所以这里不会忽略负权边, 解决了负权边问题

输入 : v[n]; u[n]; w[n], 分别表示: 一条边的两个顶点, 边的权重

输出: dis, 源点到其他点的最短路径

核心代码:

for(k = 0; k <= n; k++)
    for(i = 0; i < m; i++)
        if(dis[v[i]] > dis[u[i]] + w[i])
            dis[v[i]] = dis[u[i]] + w[i];

4. 路径记录:

在松弛操作的时候, 记录该点前一个点即可:

如 Dijkstra 松弛部分:

vector<int> path[n]
//....sth to do....

	for(int v = 0; v < n; v++){
		// 松弛部分
        if(visit[v] == false && e[u][v] != inf){
            // next,your code depends on needs
            if(dis[v] > e[u][v] + dis[u]){ //松弛操作
                dis[v] = e[u][v] + dis[u];
                // 记录前一条
                path[v].clear();
                path[v].push_back(u);
            }else if(dis[v] ==  e[u][v] + dis[u]){  //有多条路径时
            	path[v].push_back(u);
            }
        }
    }
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值