最短路之Floyd,Dijkstra(朴素+队列优化)

【Floyd】

Floyd算法是一种在有向图中求最短路径的算法。相比不能再有向图中包含负权值的dijkstra算法,Floyd算法可以用在拥有负权值的有向图中求解最短路径(不过不能包含负权回路)。它是一种求解有向图中点与点之间最短路径的算法。

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <cmath>
 5 #include <set>
 6 #include <map>
 7 #include <vector>
 8 #include <stack>
 9 #include <queue>
10 #include <algorithm>
11 #include <functional>
12 #include <cstdlib>
13 #include <string>
14 using namespace std;
15 typedef long long ll;
16 
17 const int maxn=20;
18 const int inf=0x3f3f3f3f;
19 int mp[maxn][maxn],path[maxn][maxn];
20 int n,m;
21 
22 void init(){
23     for(int i=0;i<n;i++){
24         for(int j=0;j<n;j++){
25             if( i==j ) mp[i][j]=0;
26             else mp[i][j]=inf;
27         }
28     }
29 }
30 
31 void Floyd(){
32     for(int k=0;k<n;k++){
33         for(int i=0;i<n;i++){
34             for(int j=0;j<n;j++){
35                 if( mp[i][j]>mp[i][k]+mp[k][j]){
36                     mp[i][j]=mp[i][k]+mp[k][j];
37                     path[i][j]=k;///记录能松弛的点
38                 }
39             }
40         }
41     }
42 }
43 
44 void print(int a,int b){
45     if( path[a][b]==-1 ) return;
46     print(a,path[a][b]);///前半部分
47     printf("%d-->",path[a][b]);///输出该点
48     print(path[a][b],b);///后半部分
49 }
50 
51 int main()
52 {
53     scanf("%d%d",&n,&m);
54     memset(path,-1,sizeof(path));
55     init();
56     int _start,_end,dis;
57     for(int i=0;i<m;i++){
58         scanf("%d%d%d",&_start,&_end,&dis);
59         mp[_start][_end]=dis;
60     }
61     Floyd();
62     printf("The shortest path between vertices
");
63     for(int i=0;i<n;i++){
64         for(int j=0;j<n;j++){
65             if( mp[i][j]==inf ){///两者不通
66                 printf("%d %d",i,j);
67                 printf(" These two points cannot be reached

");
68                 continue;
69             }
70             printf("%d to %d shortest path is %d
",i,j,mp[i][j]);
71             printf("The specific path is
");
72             printf("%d-->",i);
73             print(i,j);
74             printf("%d
",j);
75         }
76     }
77     return 0;
78 }

【朴素Dijkstra】

 1 #include <bits/stdc++.h>
 2 #include <iostream>
 3 #include <cstdio>
 4 #include <algorithm>
 5 using namespace std;
 6 typedef long long ll;
 7 const int maxn=1005;
 8 const int inf=0x3f3f3f3f;
 9 int mp[maxn][maxn];
10 int vis[maxn], dis[maxn];
11 int n,m;
12 
13 void init(){
14     memset(mp,0x3f,sizeof(mp));
15     for(int i=1;i<=n;i++){
16         mp[i][i]=0;
17     }
18 }
19 
20 void getmap(){///无向图
21     int u,v,w;
22     for(int i=1;i<=m;i++){
23         scanf("%d%d%d",&u,&v,&w);
24         if( mp[u][v]>w ){
25             mp[u][v]=w;
26             mp[v][u]=w;
27         }
28     }
29 }
30 
31 void dijkstra(int u){
32     memset(vis,0,sizeof(vis));
33     for(int i=1;i<=n;i++){
34         dis[i]=mp[u][i];
35     }
36     vis[u]=1;
37     for(int i=1;i<n;i++){///n个顶点松弛n-1次
38         int minn=inf, temp;
39         for(int j=1;j<=n;j++){
40             if( !vis[j] && dis[j]<minn ){
41                 minn=dis[j];
42                 temp=i;
43             }
44         }
45 
46         vis[temp]=1;
47         for(int j=1;j<=n;j++){
48             if( mp[temp][j]+dis[temp]<dis[j]){
49                 dis[j]=mp[temp][j]+dis[temp];
50             }
51         }
52     }
53 }
54 
55 int main()
56 {
57     scanf("%d%d",&n,&m);
58     init();
59     getmap();
60     dijkstra(n);
61     printf("%d
",dis[1]);
62     return 0;
63 }

【队列优化Dijkstra】

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <ctime>
 4 #include <algorithm>
 5 #include <string>
 6 #include <cstring>
 7 #include <bits/stdc++.h>
 8 typedef long long ll;
 9 
10 const int maxn = 100100;
11 const ll INF = 1e18+9;
12 using namespace std;
13 
14 ll x[maxn],y[maxn],z[maxn];
15 vector<pair<ll,ll> >v[maxn];
16 priority_queue<pair<ll,ll> >Q;
17 ll n,m;
18 ll length[maxn];
19 
20 int dij(){
21 
22     ll i;
23     for(i=0;i<=n;i++){
24         v[i].clear();
25         length[i] = INF;
26     }
27 
28     for(i=1; i<=m; i++){
29         v[x[i]].push_back(make_pair(y[i],z[i]));///点.点.距离
30         v[y[i]].push_back(make_pair(x[i],z[i]));
31     }
32     Q.push(make_pair(0,1));///first是距离,second是点
33     length[1] = 0;
34 
35     while( !Q.empty()){
36         ll a, b, c, d;
37         a = Q.top().second;
38         b = Q.top().first;
39         Q.pop();
40         if( b>length[a] ) continue;
41         for( i=0;i<v[a].size(); i++){
42             c = v[a][i].first;
43             d = v[a][i].second;
44             if( length[c]>length[a]+d ){
45                 length[c] = length[a]+d;
46                 Q.push(make_pair(-length[c],c));///优先队列从大到小排,为了从小到大排,我们存入一个负的值
47             }
48         }
49     }
50     return length[n];
51 }
52 
53 int main()
54 {
55     scanf("%lld%lld",&n,&m);
56     for(int i=1;i<=m;i++){
57         scanf("%lld%lld%d",&x[i],&y[i],&z[i]);
58     }
59     ll f=dij();
60     printf("%lld
",f);
61 
62     return 0;
63 }

PS:输出路径Dijkstra

 1 /*输出路径:朴素做法也是一样的记录路径,输出路径*/
 2 #include <iostream>
 3 #include <cstdio>
 4 #include <ctime>
 5 #include <algorithm>
 6 #include <string>
 7 #include <cstring>
 8 #include <bits/stdc++.h>
 9 typedef long long ll;
10 
11 const int maxn = 100100;
12 const ll INF = 1e18+9;
13 using namespace std;
14 
15 ll x[maxn],y[maxn],z[maxn],path[maxn];
16 vector<pair<ll,ll> >v[maxn];
17 priority_queue<pair<ll,ll> >Q;
18 ll n,m;
19 ll length[maxn];
20 
21 int dij(){
22 
23     ll i;
24     for(i=0;i<=n;i++){
25         v[i].clear();
26         length[i] = INF;
27     }
28 
29     for(i=1; i<=m; i++){
30         v[x[i]].push_back(make_pair(y[i],z[i]));///点.点.距离
31         v[y[i]].push_back(make_pair(x[i],z[i]));
32     }
33     Q.push(make_pair(0,1));///first是距离,second是点
34     path[1]=1;
35     length[1] = 0;
36 
37     while( !Q.empty()){
38         ll a, b, c, d;
39         a = Q.top().second;
40         b = Q.top().first;
41         Q.pop();
42         if( b>length[a] ) continue;
43         for( i=0;i<v[a].size(); i++){
44             c = v[a][i].first;
45             d = v[a][i].second;
46             if( length[c]>length[a]+d ){
47                 length[c] = length[a]+d;
48                 path[c]=a;///记录路径
49                 Q.push(make_pair(-length[c],c));///优先队列从大到小排,为了从小到大排,我们存入一个负的值
50             }
51         }
52     }
53     return length[n];
54 }
55 
56 int main()
57 {
58     scanf("%lld%lld",&n,&m);
59     for(int i=1;i<=m;i++){
60         scanf("%lld%lld%d",&x[i],&y[i],&z[i]);
61     }
62     ll f=dij();
63     printf("%lld
",f);
64     int p[maxn],k=0;///以下为输出路径
65     int temp = n;
66     p[k++] = temp;
67     while( path[temp]!=temp ){
68         p[k++] = path[temp];
69         temp = path[temp];
70     }
71 
72     for(int i=k-1;i>=0;i--){
73         if( i==k-1 ) printf("%d",p[i]);
74         else printf("-->%d",p[i]);
75     }
76     printf("
");
77     return 0;
78 }
View Code

无向图只是有向图的一种特殊形式,这两种算法都可以用

原文地址:https://www.cnblogs.com/wsy107316/p/12243149.html