diff --git a/lemon/bellman_ford.h b/lemon/bellman_ford.h --- a/lemon/bellman_ford.h +++ b/lemon/bellman_ford.h @@ -770,44 +770,34 @@ return (*_dist)[v] != OperationTraits::infinity(); } - // TODO: implement negative cycle -// /// \brief Gives back a negative cycle. -// /// -// /// This function gives back a negative cycle. -// /// If the algorithm have not found yet negative cycle it will give back -// /// an empty path. -// Path negativeCycle() { -// typename Digraph::template NodeMap state(*digraph, 0); -// for (ActiveIt it(*this); it != INVALID; ++it) { -// if (state[it] == 0) { -// for (Node t = it; predArc(t) != INVALID; t = predNode(t)) { -// if (state[t] == 0) { -// state[t] = 1; -// } else if (state[t] == 2) { -// break; -// } else { -// p.clear(); -// typename Path::Builder b(p); -// b.setStartNode(t); -// b.pushFront(predArc(t)); -// for(Node s = predNode(t); s != t; s = predNode(s)) { -// b.pushFront(predArc(s)); -// } -// b.commit(); -// return true; -// } -// } -// for (Node t = it; predArc(t) != INVALID; t = predNode(t)) { -// if (state[t] == 1) { -// state[t] = 2; -// } else { -// break; -// } -// } -// } -// } -// return false; -// } + /// \brief Gives back a negative cycle. + /// + /// This function gives back a directed cycle with negative total + /// length if the algorithm has already found one. + /// Otherwise it gives back an empty path. + lemon::Path negativeCycle() { + typename Digraph::template NodeMap state(*_gr, -1); + lemon::Path cycle; + for (int i = 0; i < int(_process.size()); ++i) { + if (state[_process[i]] != -1) continue; + for (Node v = _process[i]; (*_pred)[v] != INVALID; + v = _gr->source((*_pred)[v])) { + if (state[v] == i) { + cycle.addFront((*_pred)[v]); + for (Node u = _gr->source((*_pred)[v]); u != v; + u = _gr->source((*_pred)[u])) { + cycle.addFront((*_pred)[u]); + } + return cycle; + } + else if (state[v] >= 0) { + break; + } + state[v] = i; + } + } + return cycle; + } ///@} }; diff --git a/test/bellman_ford_test.cc b/test/bellman_ford_test.cc --- a/test/bellman_ford_test.cc +++ b/test/bellman_ford_test.cc @@ -220,8 +220,64 @@ } } +void checkBellmanFordNegativeCycle() { + DIGRAPH_TYPEDEFS(SmartDigraph); + + SmartDigraph gr; + IntArcMap length(gr); + + Node n1 = gr.addNode(); + Node n2 = gr.addNode(); + Node n3 = gr.addNode(); + Node n4 = gr.addNode(); + + Arc a1 = gr.addArc(n1, n2); + Arc a2 = gr.addArc(n2, n2); + + length[a1] = 2; + length[a2] = -1; + + { + BellmanFord bf(gr, length); + bf.run(n1); + StaticPath p = bf.negativeCycle(); + check(p.length() == 1 && p.front() == p.back() && p.front() == a2, + "Wrong negative cycle."); + } + + length[a2] = 0; + + { + BellmanFord bf(gr, length); + bf.run(n1); + check(bf.negativeCycle().empty(), + "Negative cycle should not be found."); + } + + length[gr.addArc(n1, n3)] = 5; + length[gr.addArc(n4, n3)] = 1; + length[gr.addArc(n2, n4)] = 2; + length[gr.addArc(n3, n2)] = -4; + + { + BellmanFord bf(gr, length); + bf.init(); + bf.addSource(n1); + for (int i = 0; i < 4; ++i) { + check(bf.negativeCycle().empty(), + "Negative cycle should not be found."); + bf.processNextRound(); + } + StaticPath p = bf.negativeCycle(); + check(p.length() == 3, "Wrong negative cycle."); + check(length[p.nth(0)] + length[p.nth(1)] + length[p.nth(2)] == -1, + "Wrong negative cycle."); + } +} + int main() { checkBellmanFord(); checkBellmanFord(); + checkBellmanFordNegativeCycle(); return 0; }