我有以下有向图,每个节点都有一个或多个属性。我尝试修改bfs算法以查找从起始节点到覆盖给定属性的所有可能路径。我也希望我发现的路径不是循环的一部分。
对于此图,如果我从节点1开始并且我想覆盖attr 4,我的算法将找到的路径是:
1-2-3
1-2-5-3
1-2-5-6-8
如果我添加边3-1
,那么路径1-2-3
和1-2-5-3
我不想被接受,因为它是循环的一部分。所以在我的算法中,我尝试检查上次访问的节点的邻居,如果邻居已经访问过,那么我尝试丢弃此路径,但我的算法在这种情况下不起作用。如果我添加边3-1
,它将返回相同的路径。我怎样才能解决这个问题?
这是我的代码:
G = nx.DiGraph()
G.add_edge(1,2)
G.add_edge(2,3)
G.add_edge(2,5)
G.add_edge(3,4)
G.add_edge(5,3)
G.add_edge(5,6)
G.add_edge(5,7)
G.add_edge(6,8)
G.add_edge(3,1)
def checkIfRequiredAttrsAreCovered(path, attrsToBeCovered):
coveredAttrs = []
counter = 0
for node in path:
coveredAttrs.extend(G.node[node]['attrs'])
for i in attrsToBeCovered:
if i in coveredAttrs:
counter = counter + 1
if counter == len(attrsToBeCovered):
return True
else:
return False
def bfs(G, startingNode, attrsToBeCovered):
paths = []
q = queue.Queue()
q.put([startingNode])
while not q.empty():
v = q.get()
if checkIfRequiredAttrsAreCovered(v, attrsToBeCovered) == True:
for i in G.neighbors(v[-1]):
if i in v:
break
paths.append(v) #print(v)
else:
for node in G.neighbors(v[-1]):
if node not in v:
path = []
path.extend(v)
path.append(node)
q.put(path)
print(paths)
答案 0 :(得分:1)
我假设您不关心节点是否是更大周期的一部分。例如。如果4连接到1,则3连接到1-2-3-4。如果要处理此问题,可以从每个匹配节点启动dfs,并将当前路径设置为已访问。
首先,you should use snake case in Python
其次,您应该使用set
来比较要涵盖的属性所涵盖的属性。对于路径,计算覆盖属性集并比较集:
def check_if_required_attrs_are_covered(G, path, attrs_to_be_covered): # be sure to pass G as an argument here
covered_attrs = set([G.node[n]['attrs'] for n in path])
return covered_attrs >= attrs_to_be_covered
第三,对bfs
函数的一些评论:
if b == True:
相当于if b:
,因为对于布尔值b == (b == True)
(尝试使用True和False来说服自己)q
路径的方式可缩短为q.put(v+ [node])
queue
:使用列表for i in G.neighbors(v[-1]):
循环。
无论您是否break
,都可以转到paths.append(v)
行。
这就是为什么你不排除带循环的路径。您希望区分循环的正常结束和中断。
这是Python中机密循环语法的完美案例:for...else
loop。
我引用了文档:“当没有break
发生时,循环的else子句运行”。这给出了以下代码:
for i in G.neighbors(v[-1]):
if i in v:
break
else: # no neighbor from v[-1] in v
yield v # instead of paths.append(v)
但您也可以使用any
获得更自然的表达方式:
if not any(i in v for i in G.neighbors(v[-1])):
yield v # instead of paths.append(v)
这给出了以下代码:
def bfs(G, starting_node, attrs_to_be_covered):
q = [[starting_node]]
while q:
v = q.pop()
if check_if_required_attrs_are_covered(G, v, attrs_to_be_covered): # be sure to pass G as an argument
if not any(i in v for i in G.neighbors(v[-1])):
yield v
else:
for node in G.neighbors(v[-1]):
if node not in v:
q.append(v+ [node])
尝试使用:
print (list(bfs(G, 1, set(["attr4"]))))