我正在实现一个图类,并且想编写一个计算给定路径是否有效的函数。我的is_path_valid函数出现关键错误。
我的图表示为{a:{b:c}},其中a和b是相互连接的顶点,c是边缘的权重
给出:
{0: {1: 5.0, 2: 10.0}, 1: {3: 3.0, 4: 6.0}, 3: {2: 2.0, 4: 2.0, 5: 2.0}, 4: {6: 6.0}, 5: {6: 2.0}, 7: {9: 1.0}, 8: {7: 2.0, 9: 4.0}}
顶点2到3是有效路径。
我的图类:
class Graph:
def __init__(self, n):
"""
Constructor
:param n: Number of vertices
"""
self.order = n
self.size = 0
self.vertex = {}
def insert_edge(self, u, v, w): #works fine
if u in self.vertex and v < self.order:
if not v in self.vertex[u]:
self.vertex[u][v] = w
self.size += 1
elif u not in self.vertex and u < self.order and v < self.order:
self.vertex[u] = {}
self.vertex[u][v] = w
self.size += 1
else:
raise IndexError
def is_path_valid(self, path):
while True:
try:
s = path.pop(0)
except IndexError:
break
if path:
d = path.pop(0)
if s not in self.vertex and d not in self.vertex[s]: #ERROR
return False
s = d
return True
我的主要功能:
def main():
g = Graph(10)
g.insert_edge(0,1,5.0)
g.insert_edge(0,2,10.0)
g.insert_edge(1,3,3.0)
g.insert_edge(1,4,6.0)
g.insert_edge(3,2,2.0)
g.insert_edge(3,4,2.0)
g.insert_edge(3,5,2.0)
g.insert_edge(4,6,6.0)
g.insert_edge(5,6,2.0)
g.insert_edge(7,9,1.0)
g.insert_edge(8,7,2.0)
g.insert_edge(8,9,4.0)
True(g.is_path_valid([0, 2]))
True(g.is_path_valid([2, 3]))
True(g.is_path_valid([0, 2, 3]))
False(g.is_path_valid([0, 1, 8]))
False(g.is_path_valid([0, 4, 3]))
print(g.vertex) #to see the graph
print(g.is_path_valid([2,3]))
if __name__ == '__main__':
main()
我的错误:
if s not in self.vertex and d not in self.vertex[s]:
KeyError: 2
答案 0 :(得分:1)
您只是将弧线和边缘混合在一起,这会导致某些意外情况发生,因此您必须在两者之一之间进行选择。
另一方面,您可以有一个定向的图,并且仍然有一个可以添加“边”的函数,因为它会同时添加两个弧(u,v)和(v,u)。我在引号中有边,因为它们并不是真正的边(术语“边”仅在无方向图中具有含义)。
from collections import defaultdict
class Graph:
def __init__(self):
self._arcs = defaultdict(dict)
def insert_arc(self, u, v, w):
self._arcs[u][v] = w
def is_arc(self, u, v):
return u in self._arcs and v in self._arcs[u]
def is_path_valid(self, path):
for u, v in zip(path, path[1:]):
if not self.is_arc(u, v):
return False
return True
# We add the notion of "edges" with the following methods:
def insert_edge(self, u, v, w):
self.insert_arc(u, v, w)
self.insert_arc(v, u, w)
@property
def edges(self):
return {((u, v), w) for u, Nu in self._arcs.items() for v, w in Nu.items() if self.is_edge(u, v)}
def is_edge(self, u, v):
is_symetric = self.is_arc(u, v) and self.is_arc(v, u)
if not is_symetric:
return False
return self._arcs[u][v] == self._arcs[v][u]
您现在可以在图形中添加边缘或弧形:
g = Graph()
# This is an arc:
g.insert_arc(1, 8, 1.)
# Weight is not symmetric but this still look like an edge:
g.insert_arc(1, 0, 3.)
g.insert_arc(0, 1, 2.)
# These are all symmetric (ie. "edges")
g.insert_edge(1, 2, 7.)
g.insert_edge(2, 3, 5.)
g.insert_edge(0, 3, 13.)
# we added an arc (1, 8):
print(g.is_path_valid([1, 8])) # True
print(g.is_path_valid([8, 1])) # False
# All true:
print(g.is_path_valid([0, 3]))
print(g.is_path_valid([2, 3]))
print(g.is_path_valid([0, 1, 2, 3, 0]))
# Adding one step make this false since (0, 2) doesn't exist:
print(g.is_path_valid([0, 1, 2, 3, 0, 2]))
我们可以使用edges
属性来找到所有“边缘”(在两个方向上具有相同权重的对称弧):
>>> print(g.edges)
{((3, 0), 13.0), ((3, 2), 5.0), ((2, 1), 7.0), ((1, 2), 7.0), ((2, 3), 5.0), ((0, 3), 13.0)}
请注意(0, 1)
不在边缘集合中的原因,这是因为链接在两个方向上都存在,但权重并不相同。弧(1, 8)
显然不在这里,因为(8, 1)
不在图形中。