zoukankan      html  css  js  c++  java
  • 最短路问题

    符号说明

    • V表示点集,E表示边集
    • 斜体表示有坑待填

    Dijkstra

    • vis数组的理解

      先把V分成两组:

      • S:已求出最短路径的顶点的集合
      • V-S=T:尚未确定最短路径的顶点集合

      将T中顶点按最短路径递增的次序加入到S中

      即用T集合中距离源点最近的更新所有边,并把这个最近点放入S中

      因为刚开始S为空,所以最外层为循环为V次

    • 堆优化

      即把求最近点的过程放入小根堆中,vis数组一样适用

    • 有一点 BFS

    • 斐波那契堆

    //normal
    dis[s]=0;
    for(int i=0;i<n;i++)
    {
        int minj=0,mindis=inf;
        for(int j=1;j<=n;j++)
            if(dis[j]<mindis && !vis[j])
            {
                mindis=dis[j];
                minj=j;
            }
        for(int j=head[minj];j!=-1;j=edge[j].nex)
            if!vis[edge[i].v] && (dis[edge[j].v]>dis[minj]+edge[j].w)
                dis[edge[j].v]=dis[minj]+edge[j].w;
        vis[minj]=true;
    }
    //heap
    for(dis[s]=0,q.push(nodeq{s,dis[s]});!q.empty();q.pop())
    {
        nodeq tmp=q.top();
        if(vis[tmp.i])continue;
        for(int i=head[tmp.i];i!=-1;i=edge[i].nex)
        {
            if(!vis[edge[i].v] && dis[tmp.i]+edge[i].w<dis[edge[i].v])
            {
                dis[edge[i].v]=dis[tmp.i]+edge[i].w;
                q.push(nodeq{edge[i].v,dis[edge[i].v]});
            }
        }
        vis[tmp.i]=true;
    }
    

    Bellman-Ford

    • 就是不断地进行松弛操作
    • 实际上是一个建树过程
    • 一点优化:一轮中未发生松弛则退出循环
    • 判负环:枚举所有边,若能松弛,则存在负环
    • 因为树最多有V-1条边,所以最外层为循环为V-1次
    for(int i=0;i<n-1;i++){
        bool flag=false;
        for(int j=0;j<2*m;j++){
            if(dis[edge[j].u]<inf){
                dis[edge[j].v]=min(dis[edge[j].v],dis[edge[j].u]+edge[j].w);
                flag=true;
            }
        }
        if(!flag)break;
    }
    

    SPFA

    • 上面的BF算法实际是一个建树过程,那么轮数小于节点深度的松弛实际上是没有用处的,SPFA就是用队列保存需要松弛的边
    • 入队:vis[i]=true 出队:vis[i]=false
    • 关于队列中相同的点只有一个:入队-->需要更新-->队列中已有的那个会负责更新
    • dfs优化
    //normal
    dis[s]=0;
    for(q.push(s);!q.empty();q.pop())
    {
        int u=q.front();
        for(int i=head[u];i!=-1;i=edge[i].nex)
        {
            if(dis[u]+edge[i].w<dis[edge[i].v])
            {
                dis[edge[i].v]=dis[u]+edge[i].w;
                if(!vis[edge[i].v])
                {
                    q.push(edge[i].v);
                	vis[edge[i].v]=true;
                }
            }
        }
        vis[u]=false;
    }
    //slf
    dis[s]=0;
    for(deq.push_back(s);!deq.empty();deq.pop_front())
    {
        int u=deq.front();
        for(int i=head[u];i!=-1;i=edge[i].nex)
        {
            if(dis[u]+edge[i].w<dis[edge[i].v])
            {
                dis[edge[i].v]=dis[u]+edge[i].w;
                if(!vis[edge[i].v])
                {
                    if(dis[edge[i].v]<dis[q.front()])
                        deq.push_front(edge[i].v);
                    else
                        deq.push_back(edge[i].v);
                    vis[edge[i].v]=true;
                }
            }
        }
        vis[u]=false;
    }
    

    Floyd

    • k在外层(dis(A,C)!=9

    for(int k=0;k<n;k++)
      for(int i=0;i<n;i++)
        for(int j=0;j<n;j++)
          if(!(dist[i][k]==Inf||dist[k][j]==Inf) && dis[i][k]+dis[k][j]<dis[i][j])
            dis[i][j]=dis[i][k]+dis[k][j];
    

    其他

    • 路径保存:松弛操作时记录该节点的父亲节点

    • 链式前向星:

      //有向
      struct node{int v;llg w;int nex;}edge[maxm];
      int head[maxn],cnt;
      void add(int u,int v,llg w){
          edge[cnt].v=v;
          edge[cnt].w=w;
          edge[cnt].nex=head[u];
          head[u]=cnt++;
      }
      
    • 参考https://www.cnblogs.com/five20/p/7782931.html

  • 相关阅读:
    奇异值分解(SVD)与在降维中的应用
    拉格朗日乘子法&KKT条件
    有监督学习、无监督学习、半监督学习
    LSTM学习—Long Short Term Memory networks
    Ubuntu16.04+CUDA8.0+cuDNN5.1+Python2.7+TensorFlow1.2.0环境搭建
    激活函数
    C基础学习笔记
    Hive
    Fragment跳转至Activity片段随笔
    冒泡排序和选择排序
  • 原文地址:https://www.cnblogs.com/intmian/p/ShortestPaths.html
Copyright © 2011-2022 走看看