简体   繁体   English

我使用哪种增强图算法?

[英]Which boost graph algorithm do I use?

I have a set of nodes AG, Z, with weighted edges defined, where AG are various nodes in a funnel, with Z at the very bottom. 我有一组节点AG,Z,其中定义了加权边,其中AG是漏斗中的各种节点,Z位于最底部。

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. 可视化具有各种边缘的漏斗(V形),但最终指向最终节点Z,就像水流向单点Z.我们希望找到最便宜的路径,直到Z,覆盖漏斗中的所有节点。

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? 我应该使用哪种增强图算法来找到这个问题的最佳边缘集?

  • ABDEZ is a cheap path that covers a lot of nodes ABDEZ是一条覆盖大量节点的廉价路径
  • CGZ is a bit forced as G only has one path to Z CGZ有点被迫,因为G只有一条到Z的路径
  • FZ looks cheap, but then we notice that since CGZ is forced, FGZ is actually cheaper than FZ (since we don't need to double-count the GZ segment, the incremental cost of FG is only 1) FZ看起来便宜,但后来我们注意到,由于CGZ被迫,FGZ实际上比FZ便宜(因为我们不需要对GZ段进行双重计算,FG的增量成本仅为1)

So, the set of edges should be (AB, BD, DE, EZ, CG, FG, GZ) 所以,边缘集应该是(AB,BD,DE,EZ,CG,FG,GZ)

I am certain this is not a new problem: I just don't know enough graph theory to identify/name the algorithm. 我确信这不是一个新问题:我只是不知道足够的图论来识别/命名算法。

有向无环图

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. 换句话说,如果我们没有先验地指出Z是图中的最低点(通过使用箭头),并允许水在两个方向上流动(通常是真的,除非我们有阀门),那么这第二个模型将正常工作。

非导向非循环图

Of course, instead of being forced to use the old the GZ directed edge , we can now choose the new FZ undirected edge for a smaller weight. 当然,我们现在可以选择新的FZ无向边缘 ,而不是被迫使用旧的GZ定向边缘

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). 根据这些结果,如果我们真的需要指向边缘, liori的答案是对原始问题的最佳响应(即算法需要编码)。

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;
}

So, you need the cheapest way to go from Z backwards into each node. 因此,您需要以最便宜的方式从Z向后进入每个节点。 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. 您的问题等同于在DAG上查找生成树,除了您需要转换DAG以使边指向相反方向。 As explained in this answer , you should check algorithms such as Chu–Liu/Edmonds' algorithm . 本回答所述 ,您应该检查诸如Chu-Liu / Edmonds算法之类的算法

It seems that there are no ready-made algorithms in Boost Graph for that, though. 但是,似乎Boost Graph中没有现成的算法。 You'll probably need to build your own algorithm. 您可能需要构建自己的算法。

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 如果要查找覆盖最少节点数的路径,则需要进行广度优先搜索

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM