1

I have implemented a Bellman-Ford algorithm to solve a problem (with a graph), but this solution was too slow, so I have replaced the Bellman-Ford's queue with a heap (std::set) , so the solution for the shortest path will be found faster. (somehow close do Dijkstra algorithm)

Now, I insert the node number in the heap, so the default std::set will sort the nodes using their number, not their cost. Everything is fine, and the algorithm gives the corect answers.

If I impelement a custom compare function for the std::set , so that the nodes will be sorted by their distance and not by their number the algorithm does no longer provide the shortest distance to the rest of the nodes.

This is my compare function:

 struct cmp{

    bool operator() (const int &a,const int &b) const{
        return (d[Q][a] < d[Q][b] );
    }
  };
 set <int,cmp> q;

So, being a BF algorithm, the algorithm runs until no improvement can be made. Can the compare function somehow "mess" the std::set, because this is the only reason I can see why adding this comparison function will give wrong answers...

I mean, why would it work if the nodes are in a completely random order but won't work if they are ordered by their cost...

XCS
  • 27,244
  • 26
  • 101
  • 151

1 Answers1

2

As far as I recall the Bellman-Ford algorithm it updates the distance of the node. Thus, using the weight as the key for std::set<T> doesn't easily work: the search in the std::set<T> wouldn't find the respective value if you just changed the distance. What you would need to do pursue this direction is to remove the node to be updated, change the node's distance, and reinsert it afterwards. Please also note that objects in std::set<T> need to have a unique key: inserting a key which already exists will fail.

You said that you are using the std::set<int> as some sort of a priority queue. Did you have a look at std::priority_queue<T>? This is doing exactly this but it tends to be more efficient than using a std::set<T>. The problem with std::priority_queue<T> is that you can't change an objects priority: you have only access to the current top. A long time ago I had create a collection of priority queues (heaps) which included versions of the priority queues allowing changes to an object's priority (they were part of the initial libraries for Boost but they never made it through the review process). I don't know how you use your priority queue and thus I don't know whether this is reasonable direction to look at.

That said, I don't see why you would want to a std::set<T> for the Bellman-Ford algorithm anyway. My understanding is that the algorithm repeatedly goes through the graph and updates nodes with their new shortest distance. Did you have a look at Boost's implementation of the Bellman-Ford algorithm?

Dietmar Kühl
  • 150,225
  • 13
  • 225
  • 380
  • 1) I have done that too (erasing and inserting) but with no succes 2) Using set instead of a queue will make the BF reach faster the solution, in a simillar way Dijkstra's algorithm does . 3) I think the algorithm should also work if I update the distances and DON'T update the set, because even though the elements are no longer ordered the algorithm should still run until reaching the solution. – XCS Feb 12 '12 at 19:31
  • I also forgot two other things (I'll add them to the answer): the `std::set` stores only one copy of each distance, i.e. if nodes in the the set would have the same distance, the latter ones are ignored. 2. Did you look at using `st::priority_queue` as a priority queue? – Dietmar Kühl Feb 12 '12 at 23:45
  • Oh, there's also multiset. So even if in set I store unique numbers, due to the compare function the nodes can be equal, so multiset is required... This is what I've thought of before going to bed :D Hope it will work. – XCS Feb 13 '12 at 09:06
  • Ok, I solved the problem by using multiset. But there was again another problem. When I had to update an element (search,delete,insert) if there were multiple elements with the same distance multiset.erase(multiset.find(element)) would delete a RANDOM element from those with equal distance. I had to use equal_range and iterate through equal elements in multiset to find exactly the node I was looking for. – XCS Feb 13 '12 at 09:26