【模板】单源最短路 Floyd + dijkstra + spfa

单源最短路

Floyd

不可以存在负环

#include 
using namespace std;
const int N = 505;
const int inf = 0x3f3f3f3f;
int d[N][N];
int n, m;

int main() {

    cin >> n >> m;
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= n; j++)
            d[i][j] = (i == j ? 0 : inf);

    while (m--) {
        int u, v, w;
        cin >> u >> v >> w;
        d[u][v] = min(d[u][v], w); //有向图
    }

    for (int k = 1; k <= n; k++)
        for (int i = 1; i <= n; i++)
            for (int j = 1; j <= n; j++)
                d[i][j] = min(d[i][j], d[i][k] + d[k][j]);

    if (d[1][n] == inf) cout << "-1";
    else cout << d[1][n];
}

dijkstra

不能用来求最长路,不可以存在负环

namespace Dijkstra {
    const ll inf = (1ll << 60);

    int st;//起点
    int ed;//终点

    struct Edge {
        int to;
        ll dis;

        bool operator<(const Edge &b) const {
            return dis > b.dis;
        }
    };
    
    vector<Edge> e[N];

    void add(int u, int v, ll w) {
        e[u].push_back({v, w});
        e[v].push_back({u, w});
    }

    priority_queue<Edge> q;
    ll d[N];
    int inq[N];

    void init(int n) {
        for (int i = 1; i <= n; i++) {
            e[i].clear();
            inq[i] = 0;
            d[i] = inf;
        }
    }

    // 使用前 请指定 st 和 ed
    void dijkstra() {
        d[st] = 0;
        q.push({st, d[st]});
        while (!q.empty()) {
            int u = q.top().to;
            q.pop();

            if (inq[u]) continue;
            inq[u] = 1;
            for (int i = 0, sz = e[u].size(); i < sz; i++) {
                int v = e[u][i].to;
                int w = e[u][i].dis;
                if (d[v] > d[u] + w) {
                    d[v] = d[u] + w;
                    q.push({v, d[v]});
                }
            }
        }

        if (d[ed] == inf) {
            cout << "No solution" << endl;
        } else {
            cout << d[ed] << endl;
        }
    }
}
using namespace Dijkstra;

数组版

// n 50
int dis[N], vis[N];
int pre[N];//记录最短路路径

void dijkstra() {
    memset(pre, 0, sizeof pre);
    memset(dis, INF, sizeof dis);
    memset(vis, 0, sizeof vis);
    dis[1] = 0;
    pre[1] = 0;
    for (int i = 1; i < n; i++) {
        int d = INF, f = 0;
        //找到当前能够找到的最短路
        for (int j = 1; j <= n; j++) {
            if (!vis[j] && dis[j] < d) {
                d = dis[j], f = j;
            }
        }
        vis[f] = 1;
        for (int j = 1; j <= n; j++) {
            if (dis[j] > dis[f] + e[f][j]) {
                dis[j] = dis[f] + e[f][j];
                pre[j] = f;
            }
        }
    }
}

spfa

SPFA \texttt{SPFA} SPFA 算法是 Bellman-Ford \texttt{Bellman-Ford} Bellman-Ford 算法的队列优化算法的别称

图论–SPFA算法(单源最短路)

优点:
1.时间复杂度比普通的 Dijkstra \texttt{Dijkstra} Dijkstra Bellman-Ford \texttt{Bellman-Ford} Bellman-Ford
2.能够计算负权图问题
3.能够判断是否有负环 (如果某个点进入队列的次数超过N次则存在负环)

namespace SPFA { //spfa 板子
    struct edge {
        int to, next;
        int w;
    } e[N];
    int head[N], tot;

    void add(int u, int v, int w) {
        e[++tot] = {v, head[u], w};
        head[u] = tot;
    }

    /* spfa实现方法:
        1.开一个队列 先将开始的节点放入
        2.每次从队列中取出一个节点u
          遍历与u相通的v节点 查询比对dis[v] 和 dis[u]+w[u,v]
          如果dis[v]>dis[u]+w  说明需要更新操作
                    1.存入最短路
                    2.由于改变了原有的长度 所以需要往后更新 与这个节点相连的最短路
                      (即:判断下是否在队列 在就不用重复 不在就加入队列 等待更新)
                    3.在这期间可以记录这个节点的进队次数,判断是否存在负环
        3.直到队空
     * */
      
    int dis[N];//最短路
    bool vis[N]; //判断是否在队列里
    int inq[N]; //入队次数
    queue<int> q;

    bool spfa(int st) {
        memset(vis, false, sizeof(vis));
        vis[st] = true;
        memset(dis, -1, sizeof(dis));//最长路初始化 -1 最短路初始化INF
        dis[st] = 0;
        memset(inq, 0, sizeof(inq));
        inq[st] = 1;

        q.push(st);
        while (!q.empty()) {
            int u = q.front();
            q.pop();
            vis[u] = false;

            for (int i = head[u]; i; i = e[i].next) {
                int v = e[i].to;
                int w = e[i].w;

                if (dis[v] < dis[u] + w) { 
                //求最长路 dis[v] < dis[u] + w  
                //求最短路 dis[v] > dis[u] + w
                    dis[v] = dis[u] + w;

                    if (!vis[v]) {
                        q.push(v);
                        vis[v] = true;
                        ++inq[v];
                        if (inq[v] > n + 1) { // inq[v]>点的总数 (包括超级源点)
                            return false; //有正环(最长路里)或者负环(最短路里)出现 陷入死循环 无解
                        }
                    }
                }
            }
        }
        return true;
    }
}
using namespace SPFA;

你可能感兴趣的:(板子)