Floyd和Dijkstra算法实现最短路

1. 问题

  最短路,顾名思义,是求出一条最短的路。具体来说,在一张图上,给定起点s和终点t,取出权值和最小的边,使得从s能到达t。

2. 解析

  1、floyd算法

    此算法是一种比较暴力的算法,每次枚举三个点abc,如果dis(a,b)>dis(a,c)+dis(c,b),那么说明,a->b的路径中,我可以选择点c,将dis(a,b)的值更新为dis(a,c)+dis(c,b),这样的操作我们叫做松弛,就在不断枚举不断松弛中,dis(a,b)就表示a->b的最小距离。

  2、dijkstra算法

    ①.初始时,S只包含起点sU包含除s外的其他顶点,且U中顶点的距离为起点s到该顶点的距离”[例如,U中顶点v的距离为(s,v)的长度,然后sv不相邻,则v的距离为∞]

    ②.U中选出距离最短的顶点k”,并将顶点k加入到S中;同时,从U中移除顶点k

    ③.更新U中各个点到起点s的距离。之所以更新U中顶点的距离,是由于上一步中确定了k是求出最短路径的顶点,从而可以利用k来更新其它顶点的距离;如,(s,v)的距离可能大于(s,k)+(k,v)的距离

    ④.重复步骤(2)(3),直到遍历完所有顶点。

3. 设计

  1、Floyd算法

for (int i = 1; i <= n; i++) {
  for (int k = 1; k <= n; k++) {
    for (int j = 1; j <= n; j++) {
      p[k][j] = min(p[k][j], p[k][i] + p[i][j]);//松弛操作
    }
  }
}

  2、Dijkstra算法

while(队列非空){
  int a=队头的dis,b=队头的x;
  for(与点b相连的边){
    if(w+a<dis[to]){
      dis[to]=w+a;
      (dis[to],to)入队;
    }
  }
}

4. 分析

  1、毫无疑问,floyd的时间复杂度是O(n³),这个算法有优点有缺点,缺点当然是复杂度太高,效率太慢;优点是询问方便,每次询问的复杂度为O(1)。它预处理了出所有点相互之间的最短距离。

  2、Dijkstra的复杂度很容易计算,普通的复杂度为O(n²),优化点在于如何取出离集合最近的点,我采用了小根堆,可以O(1)地取出最近的点,更新操作需要O(logn),综上,堆优化后的复杂度为O(nlogn)

5. 源码

   1、Floyd

/*
author: keke
project name:Floyd算法
Time Complexity: O(n³)
*/
#include<bits/stdc++.h>
using namespace std;
#define pi acos(-1.0)
#define inf 0x3f3f3f3f
typedef long long ll;
typedef unsigned long long ull;
typedef double db;
int mo[4][2] = { -1,0,1,0,0,-1,0,1 };
//int mo[8][2] = { -1,0,1,0,-1,-1,1,1,0,-1,0,1,1,-1,-1,1 };
const int maxn = 110;
ll n, m, is, t, ans, p[maxn][maxn], a, b, c;
int main() {
#ifdef ONLINE_JUDGE
#else
    //freopen("input.txt", "r", stdin);
#endif
    ios::sync_with_stdio(0);
    cin.tie(0), cout.tie(0);
    cout << fixed << setprecision(2);
    while (cin >> n >> m) {
        for (int i = 1; i <= n; i++) {
            for (int k = 1; k <= n; k++) {
                if (i == k)p[i][k] = 0;
                else p[i][k] = 1e18;
            }
        }
        for (int i = 1; i <= m; i++) {
            cin >> a >> b >> c;
            p[a][b] = p[b][a] = min(c, p[a][b]);//二维矩阵存图
        }
        for (int i = 1; i <= n; i++) {
            for (int k = 1; k <= n; k++) {
                for (int j = 1; j <= n; j++) {
                    p[k][j] = min(p[k][j], p[k][i] + p[i][j]);//松弛操作
                }
            }
        }
        cin >> a >> b;
        if (p[a][b] == 1e18)cout << "No path" << "\n";
        else cout << p[a][b] << "\n";
    }
    return 0;
    //good job!
}

  2、Dijkstra

/*
author: keke
project name:Dijkstra算法(堆优化)
Time Complexity: O(nlog(n))
*/
#include<bits/stdc++.h>
using namespace std;
#define pi acos(-1.0)
#define inf 0x3f3f3f3f
typedef long long ll;
typedef unsigned long long ull;
typedef double db;
int mo[4][2] = { -1,0,1,0,0,-1,0,1 };
//int mo[8][2] = { -1,0,1,0,-1,-1,1,1,0,-1,0,1,1,-1,-1,1 };
const int maxn = 110;
int n, m, is, t, ans, cnt, head[maxn], a, b, c, dis[maxn];
bool vis[maxn];
struct xx {
    int t, next, w;
}xx[maxn << 1];
void add(int a, int b, int c) {//链式前向星
    xx[cnt].next = head[a];
    xx[cnt].t = b;
    xx[cnt].w = c;
    head[a] = cnt++;
}
void solve(int x, int y) {
    memset(vis, false, sizeof(vis));
    for (int i = 1; i <= n; i++)dis[i] = inf;
    priority_queue<pair<int, int>, vector<pair<int, int> >, greater<pair<int, int> > > q;
    while (!q.empty())q.pop();
    dis[x] = 0;
    q.push(make_pair(0, x));//采用堆优化
    while (!q.empty()) {
        int a = q.top().first, b = q.top().second;
        q.pop();
        if (vis[b])continue;
        vis[b] = true;
        for (int i = head[b]; ~i; i = xx[i].next) {
            int to = xx[i].t;
            if (xx[i].w + a < dis[to]) {//松弛操作
                dis[to] = a + xx[i].w;
                q.push(make_pair(dis[to], to));
            }
        }
    }
    if (dis[y] == inf)cout << "No path" << "\n";
    else cout << dis[y] << "\n";
}
int main() {
#ifdef ONLINE_JUDGE
#else
    //freopen("input.txt", "r", stdin);
#endif
    ios::sync_with_stdio(0);
    cin.tie(0), cout.tie(0);
    cout << fixed << setprecision(2);
    while (cin >> n >> m) {
        cnt = 0;
        memset(head, -1, sizeof(head));
        for (int i = 1; i <= m; i++) {
            cin >> a >> b >> c;
            add(a, b, c);
            add(b, a, c);
        }
        cin >> a >> b;
        solve(a, b);
    }
    return 0;
    //good job!
}

猜你喜欢

转载自www.cnblogs.com/powerkeke/p/12404469.html