• 最短路算法(floyed+Dijkstra+bellman-ford+SPFA)


    最短路算法简单模板

    一.floyed算法

    首先对于floyed算法来说就是最短路径的动态规划解法,时间复杂度为O(n^3) 适用于图中所有点与点之间的最短路径的算法,一般适用于点n较小的情况。

    Floyed算法有三层循环,循环的层次先后顺序也是比较重要的,分别为k ,i,j;因为dis[k][i][j]代表的是i节点到j节点的最短路如果中间经过节点k的话dis[k][i][j] =dis[k-1][i][k]+dis[k-1][k][j];否则dis[k][i][j] = dis[k-1][i][j];所以说我们要求第k个节点的话就必须先把所有的k-1求出来。而此处的三维dis数组正如背包问题一样优化为二维数组。

    对于任意两个节点i,j来说;要想从节点i到达节点j的话有两种情况:

    1. 由i直接到达j
    2. 由i经过若干个k节点到达j

    所以dis[i][j] = min(dis[i][j],dis[i][k]+dis[k][j]);

    HDU 2544 最短路 

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2544

     1 #include<iostream>
     2 #include<algorithm>
     3 #include<cstring>
     4 using namespace std;
     5 const int INF = 0x3f3f3f;
     6 int n, m, mp[110][110];
     7 void floyed()
     8 {
     9     for (int k = 1; k <= n; k++)
    10         for (int i = 1; i <= n; i++)
    11             for (int j = 1; j <= n; j++)
    12                 mp[i][j] = min(mp[i][j], mp[i][k] + mp[k][j]);
    13 }
    14 int main()
    15 {
    16     ios::sync_with_stdio(false);
    17     while ((cin >> n >> m)&&n&&m) {
    18         memset(mp, INF, sizeof(mp));
    19         for (int a, b, c, i = 0; i < m; i++) {
    20             cin >> a >> b >> c;
    21             mp[a][b] = mp[b][a] =  min(mp[a][b], c);
    22         }
    23         floyed();
    24         cout << mp[1][n] << endl;
    25     }
    26     return 0;
    27 }
    View Code

    二.Dijkstra算法

    关于Dijkstra算法(贪心)的推断过程我就不详细的讲啦,我会的别人都已经讲完了而且还比我详细,在这里向大家推荐一篇写的不错的博客!https://www.cnblogs.com/nigang/p/3658990.html

    这位博主讲的还是很详细的,图解也很清晰明了

    下面我还是通过一个例题来讲解代码吧!(同floyed例题)

    邻接矩阵的Dijkstra:

     1 #include<iostream>
     2 #include<algorithm>
     3 #include<cstring>
     4 using namespace std;
     5 const int INF = 0x3f3f3f;
     6 int n, m, mp[110][110];
     7 int dis[110], vis[110];
     8 void Dijkstra()
     9 {
    10     for (int i = 1; i <= n; i++) {
    11         vis[i] = 0; dis[i] = mp[1][i];
    12     }
    13     for (int i = 1; i <= n; i++) {
    14         int cnt = INF, k;
    15         for (int j = 1; j <= n; j++) {
    16             if (!vis[j] && dis[j] < cnt) {
    17                 cnt = dis[j];
    18                 k = j;
    19             }
    20         }
    21         vis[k] = 1;
    22         for (int j = 1; j <= n; j++) {
    23             if (!vis[j] && dis[j] > dis[k] + mp[k][j])
    24                 dis[j] = dis[k] + mp[k][j];
    25         }
    26     }
    27 }
    28 int main()
    29 {
    30     ios::sync_with_stdio(false);
    31     while ((cin >> n >> m)&&n&&m) {
    32         memset(mp, INF, sizeof(mp));
    33         for (int a, b, c, i = 0; i < m; i++) {
    34             cin >> a >> b >> c;
    35             mp[a][b] = mp[b][a] =  min(mp[a][b], c);
    36         }
    37         Dijkstra();
    38         cout << dis[n] << endl;
    39     }
    40     return 0;
    41 }
    View Code

    堆优化后的Dijkstra

     1 #include<iostream>
     2 #include<algorithm>
     3 #include<cstring>
     4 #include<bitset>
     5 #include<vector>
     6 #include<queue>
     7 
     8 using namespace std;
     9 const int INF = 1 << 30;
    10 const int maxn = 110;
    11 struct node{
    12     int to, cost;
    13     node() {}
    14     node(int a, int b) :to(a), cost(b) {}
    15     bool operator<(const node&a)const {
    16         if (cost == a.cost)return to < a.to;
    17         return cost > a.cost;
    18     }
    19 };
    20 vector<node>e[maxn];
    21 int n, m, dis[maxn];
    22 void Dijkstra(int s)
    23 {
    24     for (int i = 1; i <= n; i++)dis[i] = INF;
    25     dis[s] = 0;
    26     priority_queue<node>Q;
    27     Q.push(node(s, dis[s]));
    28     while (!Q.empty()) {
    29         node t = Q.top(); Q.pop();
    30         for (int i = 0; i < e[t.to].size(); i++) {
    31             int tmp = e[t.to][i].to;
    32             if (dis[tmp] > t.cost + e[t.to][i].cost) {
    33                 dis[tmp] = t.cost + e[t.to][i].cost;
    34                 Q.push(node(tmp, dis[tmp]));
    35             }
    36         }
    37     }
    38 }
    39 int main()
    40 {
    41     ios::sync_with_stdio(false);
    42     while ((cin >> n >> m)&&(n&&m)) {
    43         for (int i = 1; i <= n; i++)e[i].clear();
    44         for (int a, b, c, i = 0; i < m; i++) {
    45             cin >> a >> b >> c;
    46             e[a].push_back(node(b, c));
    47             e[b].push_back(node(a, c));
    48         }
    49         Dijkstra(1);
    50         cout << dis[n] << endl;
    51     }
    52     return 0;
    53 }
    View Code

    三.bellman-ford算法

    当路径当中出现负权值边的时候Dijkstra算法将不再适用,因为dijkstra由于是贪心的,每次都找一个距源点最近的点,然后将该距离定为这个点到源点的最短路径,但如果存在负权边,那就有可能先通过并不是距源点最近的一个次优点,而是这一个负权值边,所求出的结果可能就不是最短距离了。

    算法讲解https://blog.csdn.net/niushuai666/article/details/6791765

    模板:无向图。有向图的话边只需要加一次即可

     1 #include<iostream>
     2 #include<algorithm>
     3 
     4 using namespace std;
     5 const int INF = 1 << 28;
     6 const int maxn = 10005;
     7 struct node {
     8     int from, to, cost;
     9     node() {}
    10     node(int a, int b, int c) :from(a), to(b), cost(c) {}
    11 }e[maxn<<1];
    12 int n, m, dis[110];
    13 bool bellman_ford()
    14 {
    15     for (int i = 2; i <= n; i++)dis[i] = INF;
    16     dis[1] = 0;
    17     for (int i = 1; i < n; i++) {
    18         int flag = 0;
    19         for (int j = 1; j <= 2 * m; j++) {
    20             if (dis[e[j].to] > dis[e[j].from] + e[j].cost) {
    21                 dis[e[j].to] = dis[e[j].from] + e[j].cost;
    22                 flag = 1;
    23             }
    24         }
    25         if (!flag)return true;
    26     }
    27     for (int j = 1; j <= m; j++)
    28         if (dis[e[j].to] > dis[e[j].from] + e[j].cost)
    29             return false;
    30     return true;
    31 }
    32 int main()
    33 {
    34     ios::sync_with_stdio(false);
    35     while ((cin >> n >> m)&&n&&m) {
    36         for (int a, b, c, i = 1; i <= m; i++) {
    37             cin >> a >> b >> c;
    38             e[i] = node(a, b, c);
    39             e[i + m] = node(b, a, c);
    40         }
    41         bellman_ford();
    42         cout << dis[n] << endl;
    43     }
    44     return 0;
    45 }
    View Code

    四. SPFA 算法<--bellman-ford算法的优化

    一篇清晰的算法过程的讲解!https://www.cnblogs.com/bofengyu/p/5004398.html

    代码模板如下

    例题:POJ 2387

    http://poj.org/problem?id=2387

     1 #include<iostream>
     2 #include<algorithm>
     3 #include<cstring>
     4 #include<vector>
     5 #include<queue>
     6 
     7 using namespace std;
     8 const int maxn = 2010;
     9 const int INF = 0x3f3f3f3f3f;
    10 int n, m;
    11 struct node{
    12     int to, cost;
    13     node() {}
    14     node(int a, int b) :to(a), cost(b) {}
    15 };
    16 vector<node> e[maxn];
    17 int vis[maxn], f[maxn], dis[maxn];
    18 void SPFA(int s)
    19 {
    20     for (int i = 0; i < maxn; i++) {
    21         vis[i] = 0; f[i] = 0;
    22         dis[i] = INF;
    23     }
    24     dis[s] = 0;
    25     vis[s] = 1; f[s]++;
    26     queue<int>Q;
    27     Q.push(s);
    28     while (!Q.empty()) {
    29         int t = Q.front(); Q.pop();
    30         vis[t] = 0;
    31         for (int i = 0; i < e[t].size(); i++) {
    32             int tmp = e[t][i].to;
    33             if (dis[tmp] > dis[t] + e[t][i].cost) {
    34                 dis[tmp] = dis[t] + e[t][i].cost;
    35                 if (!vis[tmp]) {
    36                     vis[tmp] = 1;
    37                     Q.push(tmp);
    38                     if (++f[tmp] > n)return;
    39                 }
    40             }
    41         }
    42     }
    43     return;
    44 }
    45 int main()
    46 {
    47     ios::sync_with_stdio(false);
    48     while (cin >> m >> n) {
    49         for (int a, b, c, i = 1; i <= m; i++) {
    50             cin >> a >> b >> c;
    51             e[a].push_back(node(b, c));
    52             e[b].push_back(node(a, c));
    53         }
    54         SPFA(1);
    55         cout << dis[n] << endl;
    56     }
    57     return 0;
    58 }
    View Code
  • 相关阅读:
    commonjs promise/A 规范
    Java之抽象类
    Java中多态的用法
    Java之方法的重写
    Java中static的用法
    java中this的用法
    Java概述
    二叉排序树的创建、插入、删除
    常用排序算法
    LeetCode小白菜笔记[2]:Reverse Integer
  • 原文地址:https://www.cnblogs.com/wangrunhu/p/9507865.html
Copyright © 2020-2023  润新知