zoukankan      html  css  js  c++  java
  • 基础复习笔记-最短路

    1.最短路是什么?

    顾名思义,最短路就是求一个点到另一个点最短的路径,一半分为单源最短路和多源最短路。

    2.最短路问题如何解决?

    多源最短路问题:

    多源最短路基本只有一条路可走(当询问次数很小时例外),那就是Flyod算法了。

    Flyod

    枚举k,i,j记住k一定要在最外层就好,每一次对于一个点进行松弛操作(就是更新dis),那么时间复杂度也是比较显然的O(n^3)

    例题:luoguP2910寻宝之路

    附上该题代码:

     1 #include<cstdio>
     2 #include<algorithm>
     3 using namespace std;
     4 int a[10005],f[105][105],ans;
     5 void floyd(int n)
     6 {
     7     for(int k=1;k<=n;k++)
     8     {
     9         for(int i=1;i<=n;i++)
    10         {
    11             for(int j=1;j<=n;j++)
    12             {
    13                 f[i][j]=min(f[i][j],f[i][k]+f[k][j]);
    14             }
    15         }
    16     }
    17 }
    18 int main()
    19 {
    20     int n,m;
    21     scanf("%d%d",&n,&m);
    22     for(int i=1;i<=m;i++)
    23     {
    24         scanf("%d",&a[i]);
    25     }
    26     for(int i=1;i<=n;i++)
    27     {
    28         for(int j=1;j<=n;j++)
    29         {
    30             scanf("%d",&f[i][j]);
    31         }
    32     }
    33     floyd(n);
    34     for(int i=2;i<=m;i++)
    35     {
    36         ans+=f[a[i-1]][a[i]];
    37     }
    38     printf("%d",ans);
    39     return 0;
    40 }

    单源最短路问题:

    1.Dijkstra算法:(不能处理负边权!!!)

    Dijkstra算法的原理很简单,每一次取离原点最近的一个点,这样它已经是最短路,再用他来更新与他相邻的点的dis,不断更新下去即可。

    那么终止条件就是不会有可以更新的点,时间复杂度是(N^2),找最近点可以用堆优化,那么就可以优化为((n+m)logn)

    Dijkstra是一个相当稳定的算法,基本不会被卡死

    例题:luoguP3371最短路(弱化版)  luoguP4779最短路(标准版)

    附上两道题代码:

     1 #include<cstdio>
     2 #include<algorithm>
     3 using namespace std;
     4 struct EDGE
     5 {
     6     int to,nxt,v;
     7 }edge[500005];
     8 int head[10005],cnt,vis[10005],n,m,s;
     9 long long dis[10005];
    10 void add(int a,int b,int c)
    11 {
    12     edge[++cnt].to=b;
    13     edge[cnt].v=c;
    14     edge[cnt].nxt=head[a];
    15     head[a]=cnt;
    16 }
    17 void dijkstra()
    18 {
    19     for(int i=1; i<=n; i++)
    20     {
    21         dis[i]=2147483647;
    22     }
    23     dis[s]=0;
    24     long long minn=2147483647;
    25     int cur=s;
    26     while(vis[cur]==0)
    27     {
    28         vis[cur]=1;
    29         for(int i=head[cur]; i; i=edge[i].nxt)
    30         {
    31             dis[edge[i].to]=min(dis[cur]+edge[i].v,dis[edge[i].to]);
    32         }
    33         minn=2147483647;
    34         for(int i=1;i<=n;i++)
    35         {
    36             if(vis[i]==0&&minn>dis[i])
    37             {
    38                 minn=dis[i];
    39                 cur=i;
    40             }
    41         }
    42     }
    43 }
    44 int main()
    45 {
    46     scanf("%d%d%d",&n,&m,&s);
    47     for(int i=1; i<=m; i++)
    48     {
    49         int a,b,c;
    50         scanf("%d%d%d",&a,&b,&c);
    51         add(a,b,c);
    52     }
    53     dijkstra();
    54     for(int i=1; i<=n; i++)
    55     {
    56         printf("%lld ",dis[i]);
    57     }
    58     return 0;
    59 }
     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 int fr[100010],tl,n,m,x,y,z,s;;
     4 bool b[100010];
     5 long long d[100010];
     6 struct EDGE
     7 {
     8     int to,nxt,v;
     9 } edge[200005];
    10 void add(int x,int y,int w)
    11 {
    12     edge[++tl].to=y;
    13     edge[tl].v=w;
    14     edge[tl].nxt=fr[x];
    15     fr[x]=tl;
    16 }
    17 priority_queue< pair<int,int> > q;
    18 void dijkstra()
    19 {
    20     for(int i=1; i<=n; i++)
    21     {
    22         d[i]=1e10;
    23     }
    24     d[s]=0;
    25     q.push(make_pair(0,s));
    26     while(q.empty()==0)
    27     {
    28         int x=q.top().second;
    29         q.pop();
    30         if(b[x]==1) continue;
    31         b[x]=1;
    32         for(int i=fr[x]; i; i=edge[i].nxt)
    33         {
    34             int y=edge[i].to,l=edge[i].v;
    35             if(d[y]>d[x]+l)
    36             {
    37                 d[y]=d[x]+l;
    38                 q.push(make_pair(-d[y],y));
    39             }
    40         }
    41     }
    42 }
    43 int main()
    44 {
    45     scanf("%d%d%d",&n,&m,&s);
    46     for(int i=1; i<=m; i++)
    47     {
    48         scanf("%d%d%d",&x,&y,&z);
    49         add(x,y,z);
    50     }
    51     dijkstra();
    52     for(int i=1; i<=n; i++) printf("%lld ",d[i]);
    53     return 0;
    54 }

    2.SPFA(可以处理负边权!!!)

    虽然说最近SPFA受到了针对,出题人利用SPFA的不稳定性轻松将其卡死,但是SPFA在解决负环和差分约束等问题还是有着很重大的意义

    SPFA的原理更简单,就是开一个队列,每一次遇到dis可以更新的点就更新dis,如果它不再队列里就加入队列,当队列为空就得到了最短路。

    而判断是否存在负环也很显然,一个点被更新了n-1次,那么就说明存在负环了。

    例题:luoguP2299体委争夺战附上该题代码:

     1 #include<cstdio>
     2 #include<queue>
     3 #define maxm 200000
     4 #define maxn 2500
     5 #define inf 1e7
     6 using namespace std;
     7 
     8 int n,m,cnt;
     9 struct EDGE
    10 {
    11     int nxt,to,v;
    12 };
    13 EDGE edge[2*maxm+5];
    14 int head[maxn+5],dis[maxn+5];
    15 bool vis[maxn+5];
    16 queue<int>q;
    17 
    18 void add(int x,int y,int z)
    19 {
    20     edge[++cnt].to=y;
    21     edge[cnt].v=z;
    22     edge[cnt].nxt=head[x];
    23     head[x]=cnt;
    24 }
    25 void SPFA()
    26 {
    27     int s=1;
    28     dis[s]=0;
    29     for(int i=2;i<=n;i++)
    30     {
    31         dis[i]=inf;
    32     }
    33     q.push(s);
    34     while(!q.empty())
    35     {
    36         s=q.front();
    37         vis[s]=0;
    38         q.pop();
    39         for(int i=head[s];i;i=edge[i].nxt)
    40         {
    41             if(dis[edge[i].to]>dis[s]+edge[i].v)
    42             {
    43                 dis[edge[i].to]=dis[s]+edge[i].v;
    44                 if(vis[edge[i].to]==0)
    45                 {
    46                     vis[edge[i].to]=1;
    47                     q.push(edge[i].to);
    48                 }
    49             }
    50         }
    51     }
    52 }
    53 int main()
    54 {
    55     scanf("%d%d",&n,&m);
    56     for(int i=1;i<=m;i++)
    57     {
    58         int x,y,z;
    59         scanf("%d%d%d",&x,&y,&z);
    60         add(x,y,z);
    61         add(y,x,z);
    62     }
    63     SPFA();
    64     printf("%d
    ",dis[n]);
    65     return 0;
    66 }

    总而言之,对于不同的题目要选择最优的方法,并不存在哪个算法更重要,算法都一样好,就是看用的人了。。。

  • 相关阅读:
    P1031 均分纸牌
    P1130 红牌
    P1094 纪念品分组
    win32 公用对话框
    高性能完成端口socket服务(IOCP)
    一个简单的调试日志功能
    UI设计工具
    windows平台(不包括ARM的CE)通用的压缩和解压缩
    win api 实现 AES加密、解密,获取HASH
    win32sdk 编程整理的些资料
  • 原文地址:https://www.cnblogs.com/yufenglin/p/10597420.html
Copyright © 2011-2022 走看看