• Bellman-Ford算法


    Bellman-Ford可以求有负权的图的最短路,也可以判断是否有负环存在。

    单源最短路模板

    //从s出发到所有点的最短距离
    void BellmanFord(int s) {
        for (int i = 1; i <= n; ++i) d[i] = INF;
        d[s] = 0;
        while (true) {
            bool update = false;
            for (int i = 0; i < E; ++i) {
                edge e = es[i];
                if (d[e.from] != INF && d[e.to] > d[e.from] + e.cost) {
                    d[e.to] = d[e.from] + e.cost;
                    update = true;
                }
            }
            if (!update) break;
        }
    }

    如果没有环,最多更新n-1次,n是点的个数,如果更新了n次,证明图中有环。因为求的是最短路,所以一般判断的是负环,正环也可以判断的。

    poj3259 Wormholes

    求是否存在负环

    #include <iostream>
    #include <vector>
    #include <cstdio>
    using namespace std;
    const int INF = 0x5f5f5f5f;
    const int MAX_V = 505;
    const int MAX_E = 2705;
    
    struct edge { int from, to, cost; };
    
    vector<edge> G;
    
    int d[MAX_V];
    int V, E, W;
    
    bool BellmanFord(int n)
    {
        for (int i = 1; i <= n; ++i) d[i] = INF;
        d[1] = 0;
        for (int i = 1; i <= n; ++i) {
            for (int j = 0; j < G.size(); ++j) {
                int u = G[j].from, v = G[j].to;
                if (d[u] != INF && d[v] > d[u]+G[j].cost) {
                    d[v] = min(d[v], d[u]+G[j].cost);
                    if (i == n) return true;
                }
            }
        }
        return false;
    }
    
    int main()
    {
    //freopen("in.txt", "r", stdin);
        int t;
        scanf("%d", &t);
        while (t--) {
            G.clear();
            scanf("%d%d%d", &V, &E, &W);
            int u, v, w;
            for (int i = 0; i < E; ++ i)
            {
                scanf("%d%d%d", &u, &v, &w);
                G.push_back(edge{u, v, w});
                G.push_back(edge{v, u, w});
            }
            for (int i = 0; i < W; ++ i)
            {
                scanf("%d%d%d", &u, &v, &w);
                G.push_back(edge{u, v, -w});
            }
            if (BellmanFord(V)) puts("YES");
            else puts("NO");
        }
        return 0;
    }
    View Code

    poj1860 Currency Exchange

    求是否存在正环

    //poj1860
    #include <iostream>
    #include <cstdio>
    #include <vector>
    using namespace std;
    const int N = 105;
    const int INF = 0x5f5f5f5f;
    struct Edge {
        int from, to;
        double rate, com;
    };
    vector<Edge> G;
    double d[N];
    
    bool BellmanFord(int s, double money, int n) {
        for (int i = 1; i <= n; ++i) d[i] = 0;
        d[s] = money;
        for (int i = 1; i <= n; ++i) {
            for (int j = 0; j < G.size(); ++j) {
                int u = G[j].from, v = G[j].to;
                if (d[v] < (d[u]-G[j].com)*G[j].rate) {
                    d[v] = (d[u]-G[j].com)*G[j].rate;
                    if (i == n) return true;
                }
            }
        }
        return false;
    }
    
    int main()
    {
    //freopen("in.txt", "r", stdin);
        int n, m;
        int s;
        double money;
        while (~scanf("%d%d%d%lf", &n, &m, &s, &money)) {
            G.clear();
            while (m--) {
                int u, v;
                double r1, c1, r2, c2;
                scanf("%d%d%lf%lf%lf%lf", &u, &v, &r1, &c1, &r2, &c2);
                G.push_back((Edge){u, v, r1, c1});
                G.push_back((Edge){v, u, r2, c2});
            }
            if (BellmanFord(s, money, n)) puts("YES");
            else puts("NO");
        }
        return 0;
    }
    View Code

    Bellman-Ford的复杂度很高,可以用队列来优化(也就变成了传说中的spfa)

    模板:

    const int INF = 0x5f5f5f5f;
    const int N = 105;
    struct Edge {
        int to, cost;
    };
    vector<Edge> G[N];
    int cnt[N], pre[N], d[N];
    bool inq[N];
    bool BellmanFord(int s, int n) {
        queue<int> q;
        memset(inq, 0, sizeof inq);
        memset(cnt, 0, sizeof cnt);
        for (int i = 1; i <= n; ++i) d[i] = INF;
        d[s] = 0;
        inq[s] = true;
        q.push(s);
    
        while (q.size()) {
            int u = q.front(); q.pop();
            inq[u] = false;
            for (int i = 0; i < G[u].size(); ++i) {
                int v = G[u][i].to;
                int c = G[u][i].cost;
                if (d[u] < INF && d[v] > d[u] + c) {
                    d[v] = d[u] + c;
                    pre[v] = u;
                    if (!inq[v]) {
                        q.push(v); inq[v] = true;
                        if (++cnt[v] > n) return false; // 存在负环
                    }
                }
            }
        }
        return true;
    }

    poj1847 Tram

    #include <iostream>
    #include <cstring>
    #include <cstdio>
    #include <queue>
    using namespace std;
    const int INF = 0x5f5f5f5f;
    const int N = 105;
    struct Edge {
        int to, cost;
    };
    vector<Edge> G[N];
    int d[N];
    bool inq[N];
    bool BellmanFord(int s, int n) {
        queue<int> q;
        memset(inq, 0, sizeof inq);
        for (int i = 1; i <= n; ++i) d[i] = INF;
        d[s] = 0;
        inq[s] = true;
        q.push(s);
    
        while (q.size()) {
            int u = q.front(); q.pop();
            inq[u] = false;
            for (int i = 0; i < G[u].size(); ++i) {
                int v = G[u][i].to;
                int c = G[u][i].cost;
                if (d[u] < INF && d[v] > d[u] + c) {
                    d[v] = d[u] + c;
                    if (!inq[v]) {
                        q.push(v); inq[v] = true;
                    }
                }
            }
        }
        return true;
    }
    
    int main()
    {
    //freopen("in.txt", "r", stdin);
        int n, s, t;
        while (~scanf("%d%d%d", &n, &s, &t)) {
            for (int i = 0; i <= n; ++i) G[i].clear();
            int cnt, v;
            for (int i = 1; i <= n; ++i) {
                scanf("%d", &cnt);
                for (int j = 0; j < cnt; ++j) {
                    scanf("%d", &v);
                    G[i].push_back(Edge{v, j!=0});
                }
            }
            BellmanFord(s, n);
            printf("%d
    ", d[t]==INF ? -1 : d[t]);
        }
        return 0;
    }
    View Code
  • 相关阅读:
    HDU_2010——水仙花数
    HDU_2000——ASCII码排序sort()
    HDU_2008——数值统计
    HDU_2005——今天是今年的第几天
    HDU_2004——成绩转换
    HDU_2002——计算求的体积
    InnoDB可重复读隔离级别的底层实现原理
    nginx s reload原理
    Redis主从复制原理总结
    HTTP1.0、HTTP1.1 和 HTTP2.0 的区别
  • 原文地址:https://www.cnblogs.com/wenruo/p/5831134.html
Copyright © 2020-2023  润新知