最短路

Bellman-Ford

时间复杂度O(nm)O(nm)

struct Edge {
    int x, y, v;
}edge[10010];//存边
int n, m, k;
int dis[5010];//dis[i]表示从s到i的最短距离
int pre[5010];//记录连接该节点的上一个节点
int c[5010];
void Bellman(int s,int t) {//最多迭代n-1轮
    memset(dis, 127, sizeof(dis));
    memset(pre, 0, sizeof(pre));
    dis[s] = 0;
    while (true) {
        bool ok = false;//记录在当前的迭代过程中是否遍历,若没有,循环结束
        for (int i = 1; i <= m; i++) {
            int x = edge[i].x, y = edge[i].y, v = edge[i].v;
            if (dis[x] < 1 << 30) {
                if (dis[x] + v < dis[y]) {
                    dis[y] = dis[x] + v;
                    pre[y] = x;
                    ok = true;
                }
            }
        }
        if (!ok) break;
    }
    if (dis[t] < 1 << 30) {
        printf("%d\n", dis[t]);
        /*输出从s到t的最短路,用c存放
        int l = 0;
        for (int i = t; i != s; i=pre[i]) {
            c[++l] = i;
        }
        c[++l] = s;
        for (int i = l; i >= 1; i--) cout << c[i] << " \n"[i == 1];
        */
    }
    else printf("-1\n");
}
void solve() {
    scanf("%d%d%d", &n, &m, &k);
    for (int i = 1; i <= m; i++) {
        int x, y, v;
        scanf("%d%d%d", &x, &y, &v);
        edge[i].x = x, edge[i].y = y, edge[i].v = v;
    }
    while (k--) {
        int x, y;
        scanf("%d%d", &x, &y);
        Bellman(x, y);
    }
}

S P F A

把每一轮中新更新的节点存入队列,在每一次迭代中只考虑这些新更新的点,从而达到优化的目的,但在最坏的情况下,时间复杂度依然是O(nm)O(nm)

Dijkstra

在每一轮中,将离起点最近的(dis最小,不能是无穷大)的还不在C中的顶点加入C,并且用这个点连出去的边通过松弛操作尝试更新其他点的dis,当终点或没有点加入C时,算法结束。时间复杂度为O(n2+m)O(n^2+m)

朴素写法:

我们注意到,每次我们都要进行一个找最小的操作,那么我们完全可以通过优先队列(priority_queue)来 找最小,可以将时间复杂度优化至O((n+m)logn)O((n+m)logn)

要注意Dijkstra只能跑非负权的图,如果边权有负的要用spfa

Floyd

Last updated