我有两个顶点列表:V
和S
。
我想从V
和S
生成所有可能的有向图,因此,来自V
的每个顶点只有一个边缘,而且只有一个边缘,每个来自S
的顶点可以具有任意数量的入边和出边。结果中的每个图表都应包含来自V
和S
的所有顶点。结果可以包含连接图和断开图。
First我thought这是与powerset相关的问题,但是powerset有许多其他集合,可能只包含一个元素(我不需要那些)。
我目前的策略是:
V
的顶点之间的所有对,添加到Pairs
; S
的顶点之间的所有对,添加到Pairs
; V
和S
的顶点之间的所有对,添加到Pairs
; V
的Pairs子集,每个子集在第一个位置只有一个顶点v
的实例,顶点的一个实例{{1在任意位置的v
的第二个位置和任意顶点s
的任意数量的实例。我不确定这是对的,我想知道任何想法。
也许我可以从S
和G
创建一个完全连接的图V
,然后以某种方式从中提取子图? (也许在digraph:utils的帮助下)
P.S。我试图在Erlang中解决这个问题,因为它是我正在使用的语言,现在正在积极学习。但我很高兴在答案中看到Java,Ruby或伪代码。
答案 0 :(得分:2)
嗯,这是一个非常好的问题,但你可以在那里做一些非常好的技巧。您可以将图形显示为0
和1
的方阵,其中行数和列数是顶点数。每个1
呈现从行中的顶点到列中的顶点的边。然后,每个可能的图是具有N ^ 2个比特的一个大的二进制数,即,存在由N个顶点构成的2 ^(N ^ 2)个可能的图。现在,您可以将问题分为两部分。
S
生成所有可能的图形 - 每个图形只是一个N ^ 2位数。 V
行和列展开矩阵,并按每个1
行和列中恰好一个V
的组合乘以可能性。我需要你澄清一下。你写了 ...来自S
的每个顶点可以有任意数量的入边和出边 是否包含在任何数字中?然后我不明白结果应该包含来自V
和S
的所有顶点约束到S
没有意义,因为每个S
每个解决方案都包含作为具有零入和出边的顶点。否则,它不是所有N ^ 2位数,而只是每行和每列中至少有一个1
的位数,然后你不能将你的问题分成两部分,你必须解决S
和V
在一起。然后,可能更容易首先满足V
行和列(行和列中只有一个1
),然后将每个此解决方案乘以S
x S
矩阵解决方案当你必须在行和列中至少有一个S
时,1
会受到约束。
您可以尝试各种表示作为少量顶点的列表列表。当您将索引计算为array
时,您可以尝试R+C*N
模块,或者您可以尝试使用数组数组。对于使用二进制数组的更大数量的顶点是可行的。你甚至可以在这里试试digraph
模块。类似的方法适用于在perl中生成完全闭包图,其中使用vec
的二进制操作很糟糕。但这似乎不是因为这是一个非常不同的问题。您可能会发现一些更好的优化演示文稿,但我怀疑Erlang是非常有效地进行此类计算的最佳工具。无论如何,O(2 ^(N ^ 2))的可能性正在快速增长,因此您不必担心大矩阵的有效存储; - )
从这个角度看问题。如果您有10个顶点并假设它是V
且S
为空。然后有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,...更适合此类内存和计算密集型任务。