最短路之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\n"); 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\n\n"); 68 continue; 69 } 70 printf("%d to %d shortest path is %d\n",i,j,mp[i][j]); 71 printf("The specific path is\n"); 72 printf("%d-->",i); 73 print(i,j); 74 printf("%d\n",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=j; 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\n",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\n",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\n",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("\n"); 77 return 0; 78 }
无向图只是有向图的一种特殊形式,这两种算法都可以用