首页 > 代码库 > Bellman-Ford算法

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\n", d[t]==INF ? -1 : d[t]);    }    return 0;}
View Code

 

Bellman-Ford算法