Algorithm14.1.3 SPFA

[TOC]

最短路-SPFA

SPFA

  • 数据结构类似于Dijkstra,也是d数组和vi/vis数组
  • 首先起点入队,标记已达
  • 开始循环遍历队列,此时不用判断是否已是vis。(Dijkstra是需要判断两次的)
  • 出队,标记未达
  • 遍历到之后再次给标记已达。
int d[maxpoint], vi[maxpoint];
queue<nd> spf;
void spfa(int s) {
    for (int i = 1; i <= n; ++i) d[i] = INF;d[s] = 0;
    spf.push({0, s});vi[s] = 1;
    while (!spf.empty()) {
        nd nw = spf.front();spf.pop();
        int nwpos = nw.pos;
        vi[nwpos] = 0;
        for (int i = head[nwpos]; i; i=edge[i].next) {
            int to = edge[i].to;
            if (d[to] > d[nwpos]+edge[i].cost) {
                d[to] = d[nwpos]+edge[i].cost;
                if (!vi[to]) {spf.push({d[to], to});vi[to] = 1;}
            }
        }
    }
    for (int i = 1; i <= n; ++i) printf("%d ", d[i]);
}

区分于Dijkstra:

  • 首先上来不用管任何节点的vis,因为只是表示是否划分点集
  • 然后遍历到当前点之前要判断!vis
  • 遍历到了之后要立刻把vis置为1
  • 然后遍历到当前点的所有相邻点要判断vis,来查看是否可以放入
void dijkstra(int s) {
    for (int i = 1; i <= n; ++i) dis[i] = INF;
    dis[s] = 0;
    pq.push(nd(0, s));
    while (!pq.empty()) {
        nd nw = pq.top();pq.pop();
        int from = nw.pos;
        if (!vis[from]) {
            vis[from] = 1;
            for (int i = head[from]; i; i=edge[i].next) {
                int to = edge[i].to;
                if (dis[to] > dis[from]+edge[i].cost) {
                    dis[to] = dis[from]+edge[i].cost;
                    if (!vis[to]) pq.push(nd(dis[to], to));
                }
            }
        }
    }
    for (int i = 1; i <= n; ++i) printf("%d ", dis[i]);
}
Posted on Feb 1, 2021