生成有向图的所有可能子图,保持顶点数

时间:2011-11-03 16:24:01

标签: erlang subset directed-graph subgraph powerset

我有两个顶点列表:VS

我想从VS生成所有可能的有向图,因此,来自V的每个顶点只有一个边缘,而且只有一个边缘,每个来自S的顶点可以具有任意数量的入边和出边。结果中的每个图表都应包含来自VS的所有顶点。结果可以包含连接图和断开图。

Firstthought这是与powerset相关的问题,但是powerset有许多其他集合,可能只包含一个元素(我不需要那些)。

我目前的策略是:

  • 查找来自V的顶点之间的所有对,添加到Pairs;
  • 查找来自S的顶点之间的所有对,添加到Pairs;
  • 查找来自VS的顶点之间的所有对,添加到Pairs;
  • 以这种方式生成大小不小于V的Pairs子集,每个子​​集在第一个位置只有一个顶点v的实例,顶点的一个实例{{1在任意位置的v的第二个位置和任意顶点s的任意数量的实例。

我不确定这是对的,我想知道任何想法。

也许我可以从SG创建一个完全连接的图V,然后以某种方式从中提取子图? (也许在digraph:utils的帮助下)

P.S。我试图在Erlang中解决这个问题,因为它是我正在使用的语言,现在正在积极学习。但我很高兴在答案中看到Java,Ruby或伪代码。

1 个答案:

答案 0 :(得分:2)

嗯,这是一个非常好的问题,但你可以在那里做一些非常好的技巧。您可以将图形显示为01的方阵,其中行数和列数是顶点数。每个1呈现从行中的顶点到列中的顶点的边。然后,每个可能的图是具有N ^ 2个比特的一个大的二进制数,即,存在由N个顶点构成的2 ^(N ^ 2)个可能的图。现在,您可以将问题分为两部分。

  1. S生成所有可能的图形 - 每个图形只是一个N ^ 2位数。
  2. 然后,对于每个此图表,您可以按V行和列展开矩阵,并按每个1行和列中恰好一个V的组合乘以可能性。
  3. 我需要你澄清一下。你写了 ...来自S的每个顶点可以有任意数量的入边和出边 是否包含在任何数字中?然后我不明白结果应该包含来自VS 的所有顶点约束到S没有意义,因为每个S每个解决方案都包含作为具有零入和出边的顶点。否则,它不是所有N ^ 2位数,而只是每行和每列中至少有一个1的位数,然后你不能将你的问题分成两部分,你必须解决SV在一起。然后,可能更容易首先满足V行和列(行和列中只有一个1),然后将每个此解决方案乘以S x S矩阵解决方案当你必须在行和列中至少有一个S时,1会受到约束。

    您可以尝试各种表示作为少量顶点的列表列表。当您将索引计算为array时,您可以尝试R+C*N模块,或者您可以尝试使用数组数组。对于使用二进制数组的更大数量的顶点是可行的。你甚至可以在这里试试digraph模块。类似的方法适用于在perl中生成完全闭包图,其中使用vec的二进制操作很糟糕。但这似乎不是因为这是一个非常不同的问题。您可能会发现一些更好的优化演示文稿,但我怀疑Erlang是非常有效地进行此类计算的最佳工具。无论如何,O(2 ^(N ^ 2))的可能性正在快速增长,因此您不必担心大矩阵的有效存储; - )

    编辑:

    从这个角度看问题。如果您有10个顶点并假设它是VS为空。然后有10!个可能的图形,即3628800.如果它是S,则有大约2^100即1.2677e + 30个图形(4.0197e + 13年,如果您将生成1e + 09图形每秒)。这意味着对于任意数量的顶点而言,只有极少数顶点可能存在大量可能的图形。这里最大的问题是,你将如何处理它们。你不能存储它们,但如果是,那么你必须非常有效地存储它们。二进制字段是存储由S制作的图表的最有效方式。您可以找到具有V顶点的边的更有效方法。我将它存储为数组或列表,其中position是顶点所在的边缘,而value是顶点,其中edge到达。

    因此,您的解决方案很大程度上取决于您将对结果做些什么。我想你会以某种方式过滤掉结果,因为我无法想象你会用如此多的图表来做什么;-)我的建议是尽可能在图形生成过程中尽早过滤掉有意义的图形。这意味着您的方法应该由目的决定,以使您的结果过滤能够生成算法。

    关于这个问题的Erlang效率,如果你处理如此庞大的实体(可能的图形),你必须非常小心地管理你的内存和CPU使用。你可以使用Erlang但是在一段时间内关键部分你应该在NIF中使用C.您还应该使用更多内存友好的数据结构作为二进制文件或bignums而不是列表或元组。您还可以找到其他语言,如C,C ++,OCaml,Haskell,...更适合此类内存和计算密集型任务。