Python 如何修改Johnson';限制最大循环长度的基本循环算法?
我想修改Johnson算法中查找图中所有基本圈的部分(也复制如下),这样就不会搜索大于某个最大长度的圈Python 如何修改Johnson';限制最大循环长度的基本循环算法?,python,algorithm,graph-algorithm,networkx,Python,Algorithm,Graph Algorithm,Networkx,我想修改Johnson算法中查找图中所有基本圈的部分(也复制如下),这样就不会搜索大于某个最大长度的圈 def simple_cycles(G): def _unblock(thisnode,blocked,B): stack=set([thisnode]) while stack: node=stack.pop() if node in blocked: blocked.re
def simple_cycles(G):
def _unblock(thisnode,blocked,B):
stack=set([thisnode])
while stack:
node=stack.pop()
if node in blocked:
blocked.remove(node)
stack.update(B[node])
B[node].clear()
# Johnson's algorithm requires some ordering of the nodes.
# We assign the arbitrary ordering given by the strongly connected comps
# There is no need to track the ordering as each node removed as processed.
subG = type(G)(G.edges_iter()) # save the actual graph so we can mutate it here
# We only take the edges because we do not want to
# copy edge and node attributes here.
sccs = list(nx.strongly_connected_components(subG))
while sccs:
scc=sccs.pop()
# order of scc determines ordering of nodes
startnode = scc.pop()
# Processing node runs "circuit" routine from recursive version
path=[startnode]
blocked = set() # vertex: blocked from search?
closed = set() # nodes involved in a cycle
blocked.add(startnode)
B=defaultdict(set) # graph portions that yield no elementary circuit
stack=[ (startnode,list(subG[startnode])) ] # subG gives component nbrs
while stack:
thisnode,nbrs = stack[-1]
if nbrs:
nextnode = nbrs.pop()
# print thisnode,nbrs,":",nextnode,blocked,B,path,stack,startnode
# f=raw_input("pause")
if nextnode == startnode:
yield path[:]
closed.update(path)
# print "Found a cycle",path,closed
elif nextnode not in blocked:
path.append(nextnode)
stack.append( (nextnode,list(subG[nextnode])) )
closed.discard(nextnode)
blocked.add(nextnode)
continue
# done with nextnode... look for more neighbors
if not nbrs: # no more nbrs
if thisnode in closed:
_unblock(thisnode,blocked,B)
else:
for nbr in subG[thisnode]:
if thisnode not in B[nbr]:
B[nbr].add(thisnode)
stack.pop()
assert path[-1]==thisnode
path.pop()
# done processing this node
subG.remove_node(startnode)
H=subG.subgraph(scc) # make smaller to avoid work in SCC routine
sccs.extend(list(nx.strongly_connected_components(H)))
当然,我也会接受一个与上述实现不同但运行时间相似的建议。此外,我的项目使用networkx,因此可以随意使用该库中的任何其他函数,例如最短路径
(注意:不是家庭作业!)
编辑
Dorijan Cirkveni建议(如果我理解正确的话):
然而,这是行不通的。下面是一个反例:
G = nx.DiGraph()
G.add_edge(1, 2)
G.add_edge(2, 3)
G.add_edge(3, 1)
G.add_edge(3, 2)
G.add_edge(3, 4)
my_cycles = list(simple_cycles(G, limit = 3)) # Modification
nx_cycles = list(nx.simple_cycles(G)) # Original networkx code
print("MY:", my_cycles)
print("NX:", nx_cycles)
将输出
MY: [[2, 3]]
NX: [[1, 2, 3], [2, 3]]
此外,如果我们用
堆栈
或路径
替换阻塞的
,则此示例的结果将是正确的,但对于其他图形将给出错误的答案 您只需更改两件事:
def简单循环(G,极限):
=
而不是=
将导致函数运行,因为使用负值时没有限制,而不是不返回任何节点这是这段代码的一个经过高度修改的版本,但至少它可以工作
def simple_cycles(G, limit):
subG = type(G)(G.edges())
sccs = list(nx.strongly_connected_components(subG))
while sccs:
scc = sccs.pop()
startnode = scc.pop()
path = [startnode]
blocked = set()
blocked.add(startnode)
stack = [(startnode, list(subG[startnode]))]
while stack:
thisnode, nbrs = stack[-1]
if nbrs and len(path) < limit:
nextnode = nbrs.pop()
if nextnode == startnode:
yield path[:]
elif nextnode not in blocked:
path.append(nextnode)
stack.append((nextnode, list(subG[nextnode])))
blocked.add(nextnode)
continue
if not nbrs or len(path) >= limit:
blocked.remove(thisnode)
stack.pop()
path.pop()
subG.remove_node(startnode)
H = subG.subgraph(scc)
sccs.extend(list(nx.strongly_connected_components(H)))
def简单循环(G,极限):
subG=类型(G)(G.边()
sccs=列表(nx.强连接组件(subG))
而SCC:
scc=sccs.pop()
startnode=scc.pop()
路径=[startnode]
blocked=set()
已阻止。添加(startnode)
stack=[(startnode,list(subG[startnode]))]
堆栈时:
此节点,nbrs=堆栈[-1]
如果NBR和len(路径)<限制:
nextnode=nbrs.pop()
如果nextnode==startnode:
屈服路径[:]
elif nextnode未被阻止:
append(nextnode)
append((nextnode,list(subG[nextnode]))
已阻止。添加(下一个节点)
持续
如果不是NBR或len(路径)>=限制:
已阻止。删除(此节点)
stack.pop()
path.pop()
子g.删除节点(开始节点)
H=子g.子图(scc)
扩展(列表(nx.强连接组件(H)))
对不起-我不明白你在“奖金”评论中的意思。你能改写一下吗?这也是我的第一反应,但它不起作用。我将用更多细节更新我的问题。非常感谢。在我看来,这就像将if-nbrs
更改为if-nbrs和len(path)@Joel一样简单,不幸的是,这仍然导致了与Dorijan Cirkveni的答案相同的答案。为了获得更好的性能,我建议使用这个库:graph-tool.skewed.de
...
if blocked.size>=limit+1:
pass
elif if nextnode == startnode:
yield path[:] ...
def simple_cycles(G, limit):
subG = type(G)(G.edges())
sccs = list(nx.strongly_connected_components(subG))
while sccs:
scc = sccs.pop()
startnode = scc.pop()
path = [startnode]
blocked = set()
blocked.add(startnode)
stack = [(startnode, list(subG[startnode]))]
while stack:
thisnode, nbrs = stack[-1]
if nbrs and len(path) < limit:
nextnode = nbrs.pop()
if nextnode == startnode:
yield path[:]
elif nextnode not in blocked:
path.append(nextnode)
stack.append((nextnode, list(subG[nextnode])))
blocked.add(nextnode)
continue
if not nbrs or len(path) >= limit:
blocked.remove(thisnode)
stack.pop()
path.pop()
subG.remove_node(startnode)
H = subG.subgraph(scc)
sccs.extend(list(nx.strongly_connected_components(H)))