1. 程式人生 > >最短路算法(floyed+Dijkstra+bellman-ford+SPFA)

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

bool logs pan 動態規劃 優點 push i++ img tails

最短路算法簡單模板

一.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

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