Loading

最短路问题

符号说明

  • 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

posted @ 2019-03-30 20:28  intmian  阅读(270)  评论(0编辑  收藏  举报