最短路算法(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

 

转载于:https://www.cnblogs.com/wangrunhu/p/9507865.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值