zoukankan      html  css  js  c++  java
  • 最短路之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

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

  • 相关阅读:
    JavaScript
    monkeyrunner总结
    repo简介
    android4.4 settings 中控制卡1 卡2都振动
    卡1卡2设置不同的默认铃声
    获取布局 ActionBar
    android Settings 解析
    设置应用中出现NFC服务,去掉
    判断当前网络显示运营商
    设置中默认铃声 通知 闹钟等
  • 原文地址:https://www.cnblogs.com/wsy107316/p/12243149.html
Copyright © 2011-2022 走看看