zoukankan      html  css  js  c++  java
  • 最短路径算法

    Dijkstra算法

    时间复杂度O(N2)。

    单源最短路径算法,边权非负,基于贪心思想

    算法描述:

    设起点为s,dis[v]表示从s到v的最短路径,pre[v]为v的前驱节点,用来输出路径。

    (a)初始化:dis[v]=0x7fffffff;dis[v]=0;pre[s]=0;

    (b)for(int i=1;i<=n;i++)

       1.在未被访问过的点中找一个点u使得dis[u]是最小的。

       2.u标记为已确定最短路径。

       3.for与u相连的每个未确定最短路径的点v

          if(dis[u]+w[u][v]<dis[v]){

            dis[v]=dis[u]+w[u][v];//松弛

            pre[v]=u;//记录这条路径

          }

     

    模板题:最小花费

    code:

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #define maxn 2010
    using namespace std;
    
    int n,m,x,y,a,b,peo;//n m位总人数和可转账人对数,x y z a b见题目,peo指现在的这个人
    double minn;
    double dis[maxn],z[maxn][maxn];
    bool f[maxn];
    
    void dijkstra(int d){
        for(int i=1;i<=n;i++) dis[i]=z[d][i];
        dis[d]=1;//********
        f[d]=true;//********
        for(int i=1;i<=n-1;i++){
            minn=0.0;
            for(int j=1;j<=n;j++)
                if((!f[j])&&dis[j]>minn){
                    peo=j;
                    minn=dis[j];
                }
            f[peo]=true;
            if(peo==b) break;
            for(int j=1;j<=n;j++)
                if((!f[j])&&dis[peo]*z[peo][j]>dis[j])
                    dis[j]=dis[peo]*z[peo][j];
        }
    }
    
    int main(){
        cin>>n>>m;
        for(int i=1;i<=m;i++){
            cin>>x>>y;
            cin>>z[x][y];
            z[x][y]=(100-z[x][y])/100;//z[x][y]表示x和y转账扣完手续费后能留下的钱
            z[y][x]=z[x][y];
        }
        cin>>a>>b;
        dijkstra(a);
        printf("%.8lf
    ",100.0/dis[b]);
        return 0;
    }
    View Code

    Bellman—Ford算法

    时间复杂度O(NE),其中N是顶点数,E是边数。

    单源最短路径算法,能处理存在负边权的情况,但无法处理存在负权回路的情况,基于迭代思想

    算法描述:

    设s为起点,dis[v]为s到v的最短距离,pre[v]为v的前驱,w[j]为边j的长度,且j连接u和v。

    (a)初始化:dis[v]=0x7fffffff;dis[s]=0;pre[s]=0;

    (b)for(int i=1;i<=n-1;i++)

         for(int j=1;j<=E;j++)

           if(dis[u]+w[j]<dis[v]){

             dis[v]=dis[u]+w[j];

             pre[v]=u;

           }

    SPFA算法

    时间复杂度O(kE),其中k是一个较小的常数(所有顶点进队的频率次数),E为边数。注意,在特殊构造的图上,该算法很可能退化为O(nm)。

    单源最短路径算法,能处理存在负边权的情况,但无法处理存在负权回路的情况,是队列优化的Bellman—Ford

    算法描述:

     void spfa(){
         memset(dis,0x3f,sizeof(dis));
         memset(vis,0,sizeof(vis));
         dis[1]=0;
         vis[1]=true;
         q.push(1);
         while(q.size()){
             int x=q.front();
             q.pop();
             vis[x]=false;//取出队头
             for(int i=head[x];i;i=Next[i]){//扫描所有出边 
                 int y=ver[i],z=edge[i];
                 if(dis[y]>dis[x]+z){
                     d[y]=d[x]+z;
                     if(!vis[y]) q.push(y),vis[y]=true;
                 }
             } 
         }
     }

     

    判断有无负环:

    方法一:判断点的入队次数,若某点入队次数超过N次则存在负环。

    方法二:从起点到该点的最短路中的点数大于N。

    Floyed—Warshall算法

    时间复杂度O(N3)。

    多源最短路径算法,能处理存在负边权的情况,基于DP思想。

    算法描述:

    (a)初始化:点u和v如果有边相连,则dis[u][v]=w[u][v]。

    (b)for(int k=1;k<=n;k++)

         for(int i=1;i<=n;i++)

           for(int j=1;j<=n;j++)

             if((i!=j)&&(k!=j)&&(i!=k)&&(dis[i][k]+dis[k][j]<dis[i][j]))

               dis[i][j]=dis[i][k]+dis[k][j];

    注意:k一定要放在最外层循环!!!很重要!!!

    原理:k一次性更新了所有的点对,更新i和j时保证了i-k的距离已经被更新过了,所以f[k][i][j]表示i和j之间可通过前k个节点的最短路径。

    精髓:依次扫描每一点(k),并以该点作为中介点,计算出通过k点的其他任意两点(i,j)的最短距离。

    两种可能:1.经过第k个点不能找到最短路径,f[k][i][j]=f[k-1][i][j]

          2.经过第k个点更找到更短的路径,f[k][i][j]=f[k-1][i][k]+f[k-1][k][j]

          因为f[k]只与f[k-1]有关,所以f最外层一维空间可以省略。

    Floyed找最小环:

     for(int k=1;k<=n;k++){
         for(int i=1;i<=k-1;i++)
             for(int j=i+1;j<=k-1;j++)
                 answer=min(answer,dis[i][j]+g[i][k]+g[k][j]);//找最小环 
         for(int i=1;i<=n;i++)
             for(int j=1;j<=n;j++)
                 dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);//找最短路径 
     }

    *参考:《信息学奥赛一本通》《算法竞赛进阶指南》。

     

  • 相关阅读:
    Tomcat工作原理
    刚刚大学毕业,自己搭网站遇到的问题 一:tomcat中同时部署两个项目的问题
    maven常用命令
    修改redis端口号
    assert的基本用法
    Linux下mysql新建账号及权限设置
    tomcat设置http自动跳转为https访问
    spring mvc 实现文件上传下载
    svn: E155004 is already locked 解决方案
    数据库连接池druid
  • 原文地址:https://www.cnblogs.com/DReamLion/p/14351055.html
Copyright © 2011-2022 走看看