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

 

posted @ 2016-09-01 20:12  我不吃饼干呀  阅读(212)  评论(0编辑  收藏  举报