子图枚举
回答
这个问题有在接受答案this question一个更好的答案。它避免了在@ ninjagecko的答案中标记为“你填写上面的函数”的计算复杂步骤。它可以有效地处理有几个环的化合物。
查看链接的问题的全部细节,但这里是总结。 (N(v)表示一组顶点v的邻居,在“选择一个顶点”的步骤,你可以选择任意的顶点。)
GenerateConnectedSubgraphs(verticesNotYetConsidered, subsetSoFar, neighbors):
if subsetSoFar is empty:
let candidates = verticesNotYetConsidered
else
let candidates = verticesNotYetConsidered intersect neighbors
if candidates is empty:
yield subsetSoFar
else:
choose a vertex v from candidates
GenerateConnectedSubgraphs(verticesNotYetConsidered - {v},
subsetSoFar,
neighbors)
GenerateConnectedSubgraphs(verticesNotYetConsidered - {v},
subsetSoFar union {v},
neighbors union N(v))
什么是枚举父图的所有子图的有效算法。在我的具体情况中,父图是分子图,因此它将被连接并且通常包含少于100个顶点。
比较用数学子图:
你可以给每个元件的数目从0到N,然后枚举每个子图作为长度为N的任何二进制数你不会需要扫描图形在所有。
如果你真的想要的是具有某种属性的子图(完全连接等),那么你需要更新你的问题。正如一位评论员指出的那样,2^100非常大,所以你绝对不希望(像上面那样)列举数学上正确但物理上无聊的断开的子图。如果假设每秒钟进行十亿次计数,至少需要40万亿年才能列举出所有这些数据,否则它会从字面上把你带走。
连接 - 子发电机:
如果你想要某种枚举的,在某些指标保留子图的DAG属性,例如(1,2,3) - >(2,3) - >(2),(1,2,3) - >(1,2) - >(2),您只需要一个可以生成所有CONNECTED子图都作为迭代器(产生每个元素)。这可以通过递归地删除单个元素(可选地从“边界”)来完成,检查剩余的元素集是否在缓存中(否则添加它),产生它并递归。如果您的分子非常连锁且周期非常短,这种方法很好。例如,如果你的元素是一个N元素的五角星,它只会有(100/5)^ 5 = 320万个结果(小于1秒)。但是,如果您开始添加多个单个戒指,例如芳香族化合物和其他,你可能会很难过。
例如在python
class Graph(object):
def __init__(self, vertices):
self.vertices = frozenset(vertices)
# add edge logic here and to methods, etc. etc.
def subgraphs(self):
cache = set()
def helper(graph):
yield graph
for element in graph:
if {{REMOVING ELEMENT WOULD DISCONNECT GRAPH}}:
# you fill in above function; easy if
# there is 0 or 1 ring in molecule
# (keep track if molecule has ring, e.g.
# self.numRings, maybe even more data)
# if you know there are 0 rings the operation
# takes O(1) time
continue
subgraph = Graph(graph.vertices-{element})
if not subgraph in cache:
cache.add(subgraph)
for s in helper(subgraph):
yield s
for graph in helper(self):
yield graph
def __eq__(self, other):
return self.vertices == other.vertices
def __hash__(self):
return hash(self.vertices)
def __iter__(self):
return iter(self.vertices)
def __repr__(self):
return 'Graph(%s)' % repr(set(self.vertices))
示范:
G = Graph({1,2,3,4,5})
for subgraph in G.subgraphs():
print(subgraph)
结果:
Graph({1, 2, 3, 4, 5})
Graph({2, 3, 4, 5})
Graph({3, 4, 5})
Graph({4, 5})
Graph({5})
Graph(set())
Graph({4})
Graph({3, 5})
Graph({3})
Graph({3, 4})
Graph({2, 4, 5})
Graph({2, 5})
Graph({2})
Graph({2, 4})
Graph({2, 3, 5})
Graph({2, 3})
Graph({2, 3, 4})
Graph({1, 3, 4, 5})
Graph({1, 4, 5})
Graph({1, 5})
Graph({1})
Graph({1, 4})
Graph({1, 3, 5})
Graph({1, 3})
Graph({1, 3, 4})
Graph({1, 2, 4, 5})
Graph({1, 2, 5})
Graph({1, 2})
Graph({1, 2, 4})
Graph({1, 2, 3, 5})
Graph({1, 2, 3})
Graph({1, 2, 3, 4})
不幸的是,化合物中往往会有一个或几个环。但是在最大环数为零的情况下,你的算法应该没问题。 – Narwe 2011-05-13 13:31:04
我认为{对于子图的粗略数量,{环的直径或某物的某个最小直径,或环可能加入以形成更复杂结构的方式(例如在晶体中)}可能比环的数量更重要。这是一个单独的问题,而不是能够优化代码中上面的注释中生成连续的子图。不相关的是,由于空间结构的原因,可能会有很好的方法来基于三维空间中的嵌入来细分问题。尽管如此。 – ninjagecko 2011-05-13 18:03:49
- 1. 将枚举映射到“子枚举”
- 2. Java:旧枚举子集的新枚举
- 3. 地图枚举为[标志]枚举
- 4. 枚举图像资源枚举
- 5. UML类图枚举
- 6. 枚举prolog的子列表
- 7. 枚举Google电子表格?
- 8. 有效枚举子集
- 9. 带枚举的MySQL枚举
- 10. Java枚举找到枚举
- 11. Java类枚举枚举类
- 12. 在枚举中枚举
- 13. 转换枚举来枚举
- 14. 重新枚举枚举
- 15. C#中的枚举子集或子集
- 16. 枚举“地图”可变
- 17. 定义枚举地图
- 18. JPA地图集合枚举
- 19. 休眠3地图枚举
- 20. 在枚举语句中枚举mysql枚举
- 21. 在MVC的索引视图中的枚举到枚举
- 22. 枚举
- 23. 枚举
- 24. 枚举
- 25. 枚举
- 26. 枚举
- 27. 爪哇枚举和Objective-C枚举
- 28. 与protobuf的枚举替换C++枚举
- 29. Java的枚举和PostgreSQL枚举
- 30. 获取枚举并发送枚举值
你想要的所有子图或全部连通子? – 2011-05-12 21:12:47
无论您的效率如何,都需要花费时间来枚举2^100个顶点子集,并且在您考虑边缘可以存在与否之前。你能在太阳爆炸之前切换到可能完成的问题吗? – btilly 2011-05-12 21:27:46
@btilly:你说的对,假设它是一个顶点标记图,通常在应用程序中就是这种情况。如果顶点未被标记(即它们不可区分),则例如在n个顶点上的完整图只有n个子图(包括它本身)。 – 2011-05-13 01:53:15