6

I have a set of nodes A-G, Z, with weighted edges defined, where A-G are various nodes in a funnel, with Z at the very bottom.

Visualize a funnel (V-shaped) with various edges, but eventually pointed towards Z, the final node, like water flowing down to a single point Z. We want to find the cheapest path down to Z which covers all nodes in the funnel.

Here are the constraints:

  • There are no orphaned nodes (all nodes are connected/included)
  • We want to minimize the sum of the weighted edges
  • "Sharing edges", like water merging as it flows downwards, only counts the shared edge's weight once (in other words, it's free to flow down a wet path)

Which boost graph algorithm should I use to find the optimal set of edges for this problem?

  • A-B-D-E-Z is a cheap path that covers a lot of nodes
  • C-G-Z is a bit forced as G only has one path to Z
  • F-Z looks cheap, but then we notice that since C-G-Z is forced, F-G-Z is actually cheaper than F-Z (since we don't need to double-count the G-Z segment, the incremental cost of F-G is only 1)

So, the set of edges should be (A-B, B-D, D-E, E-Z, C-G, F-G, G-Z)

I am certain this is not a new problem: I just don't know enough graph theory to identify/name the algorithm.

Directed Acyclic Graph

Update

While researching the problem some more, I found that if the graph were not directed, the problem is reduced to a Minimum Spanning Tree. In other words, if we did not specify, a priori, that Z is the lowest point in the graph (through the use of arrows), and water were allowed to flow in both directions (generally true, unless we have valves), then this second model will work fine.

NonDirected Acyclic Graph

Of course, instead of being forced to use the old the G-Z directed edge, we can now choose the new F-Z undirected edge for a smaller weight.

In light of these results, if we truly need the edges to be directed, liori's answer is the best response for the original question (ie an algorithm needs to be coded).

Output

D <--> E with weight of 1
F <--> G with weight of 1
A <--> B with weight of 2
E <--> Z with weight of 2
C <--> G with weight of 2
F <--> Z with weight of 2
B <--> D with weight of 3
Total Weight = 13

Code for Undirected Acyclic Graph, using a Minimum Spanning Tree

#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/kruskal_min_spanning_tree.hpp>
#include <iostream>

int
main()
{
  using namespace boost;

  typedef adjacency_list < vecS, vecS, undirectedS,
    no_property, property < edge_weight_t, int > > Graph;
  typedef graph_traits < Graph >::edge_descriptor Edge;
  typedef graph_traits < Graph >::vertex_descriptor Vertex;
  typedef std::pair<int, int> E;

  char letter[] = "ABCDEFGZ";
  const int num_nodes = 8;
  E edge_array[] = { 
        E(0,1), E(1,2), E(1,3), E(3,6), E(3,5), E(3,4), E(2,5), E(2,6), 
        E(5,7), E(5,6), E(6,7), E(4,7) 
  };
  int weights[] = { 2, 6, 3, 5, 3, 1, 4, 2, 2, 1, 3, 2 };
  std::size_t num_edges = sizeof(edge_array) / sizeof(E);
  Graph g(edge_array, edge_array + num_edges, weights, num_nodes);
  property_map < Graph, edge_weight_t >::type weight = get(edge_weight, g);
  std::vector < Edge > spanning_tree;

  kruskal_minimum_spanning_tree(g, std::back_inserter(spanning_tree));

  int total_weight = 0;
  for (std::vector < Edge >::iterator ei = spanning_tree.begin();
       ei != spanning_tree.end(); ++ei) 
  {
    std::cout << letter[source(*ei, g)] << " <--> " << letter[target(*ei, g)]
      << " with weight of " << weight[*ei]
      << std::endl;
    total_weight += weight[*ei];
  }
  std::cout << "Total Weight = " << total_weight << std::endl;

  return EXIT_SUCCESS;
}
Community
  • 1
  • 1
kfmfe04
  • 14,936
  • 14
  • 74
  • 140
  • Have you decided on any algorithm at all? If so, finding the matching one in Boost should be a no-brainer. Suggestion: Tag this with "graph" and "algorithm", too, and make it a general question concerning algorithms. – Ulrich Eckhardt Jan 26 '13 at 14:49
  • @doomster thx for your tag suggestion - unfortunately, my background in graph theory is not strong enough for me to identify/name the correct algorithm (but I can describe the problem). – kfmfe04 Jan 26 '13 at 15:03
  • You want *one* path that covers all nodes? Do you have a picture of what you want? – phant0m Jan 26 '13 at 15:05
  • @phant0m no - the path(s) is/are allowed to branch/merge (like water flowing down into a funnel, but in general, branches will cost more), but every node must find its way down to Z somehow - I will try to come up with a sample case so it's easier to understand: funnelling water is the closest analogy I have atm. – kfmfe04 Jan 26 '13 at 15:08
  • Ah, I was talking about [**this**](http://en.wikipedia.org/wiki/Path_(graph_theory)). – phant0m Jan 26 '13 at 15:10
  • @phant0m - good idea: working on one – kfmfe04 Jan 26 '13 at 15:13

2 Answers2

3

So, you need the cheapest way to go from Z backwards into each node. Your problem is equivalent to finding a spanning tree on a DAG, except that you need to transform your DAG so that the edges point to the opposite direction. As explained in this answer, you should check algorithms such as Chu–Liu/Edmonds' algorithm.

It seems that there are no ready-made algorithms in Boost Graph for that, though. You'll probably need to build your own algorithm.

Community
  • 1
  • 1
liori
  • 40,917
  • 13
  • 78
  • 105
  • +1 thx for the hint - I was just investigating whether **Minimum Spanning Trees** will do the trick when you posted your answer. I may have to try coding up a MST to see if it will give me the right answer. It may turn out that Z is really like any other node and that an undirected graph is sufficient. – kfmfe04 Jan 26 '13 at 17:06
  • @phant0m: only because the usual formulation of the problem is that you go along the direction of the edges, and here you'd need to go the opposite way. – liori Jan 26 '13 at 17:24
1

This is a problem that can be solved with a Uniform Cost Search. This algorithm can be applied to any directed graph that contains at least one solution.

This will find the path of the lowest total edge cost.

If you are looking for the path that covers the least number of nodes, you would want a Breadth First Search

Kyle
  • 893
  • 1
  • 9
  • 20
  • The tricky part, however, is I am not just looking for one path from A to Z: I need the cheapest **total solution** such that all nodes can reach Z (which doesn't double-count any edges). – kfmfe04 Jan 26 '13 at 16:19
  • @kfmfe04 Then I would encourage you to look into [The Traveling Salesman Problem](http://en.wikipedia.org/wiki/Traveling_salesperson_problem) – Kyle Jan 27 '13 at 03:23
  • TSP overly restricts the solutions: a tree allows for branching (a valid solution for my problem) while the TSP does not. – kfmfe04 Jan 27 '13 at 03:30