Python 在元组列表中查找圆形路由
我有一个包含源和目标的元组列表 我需要确保没有“环形路线” 例如:Python 在元组列表中查找圆形路由,python,python-3.x,data-structures,computer-science,Python,Python 3.x,Data Structures,Computer Science,我有一个包含源和目标的元组列表 我需要确保没有“环形路线” 例如: [(1,2), (3,4), (2,3)]. is OK 但是 这是不好的,因为我们可以从1开始→ 2.→ 3.→ 1 我怀旧了,想起了我的计算机科学学位,所以我想到了图形数据结构。不幸的是,我无法使用python找到一个好的实现,我在Google上找到的所有示例(这里是stackoverflow)都只是为了找到最短路径 什么想法我能实现这个?< p>这里是Python中的一个实现,它工作得很好(也可以在java和C++中使用
[(1,2), (3,4), (2,3)]. is OK
但是
这是不好的,因为我们可以从1开始→ 2.→ 3.→ 1
我怀旧了,想起了我的计算机科学学位,所以我想到了图形数据结构。不幸的是,我无法使用python找到一个好的实现,我在Google上找到的所有示例(这里是stackoverflow)都只是为了找到最短路径
什么想法我能实现这个?
< p>这里是Python中的一个实现,它工作得很好(也可以在java和C++中使用,但是我只尝试了第一个例子)。p> 如果我理解正确,那么问题是什么时候你可以到达一个起点。为了简单明了,我将从一个简单的python开始。显而易见的暴力解决方案是检查数据中显示的每个源的所有可能目的地。当然,您需要稍微整理一下数据。那就是一条链子。下面的代码实现了这种方法def get_all_sources(data):
ans = dict()
for src, dst in data:
ans.setdefault(src, set()).add(dst)
return ans
def get_all_possible_destinations(src, all_src, ans=None):
ans = set() if ans is None else ans
for dst in all_src.get(src, set()):
if dst in ans:
continue
ans.add(dst)
get_all_possible_destinations(dst, all_src, ans)
return ans
def pipeline_source_by_source(data):
all_src = get_all_sources(data)
for src in all_src:
all_possible_destiations = get_all_possible_destinations(src, all_src)
if src in all_possible_destiations:
print(f"found problem: {src} -> {src}")
break
else:
print('no problems found')
if __name__ == '__main__':
data_list = [
[(1, 2)],
[(1, 2), (2, 3)],
[(1, 2), (3, 4), (2, 3)],
[(1, 2), (3, 4), (2, 3), (3, 1)],
[(5, 6), (5, 7), (5, 8), (5, 9), (9, 10), (10, 5)],
[(5, 6), (5, 7), (5, 8), (5, 9), (9, 10), (10, 15)]
]
for idx, data in enumerate(data_list):
print(idx)
pipeline_source_by_source(data)
结果:
0
no problems found
1
no problems found
2
no problems found
3
found problem: 1 -> 1
4
found problem: 5 -> 5
5
no problems found
这有点晚了,但给出了一个更短的解决方案(更少的Python行)。其基本原理是建立一个可直接从源访问的目的地字典(由源索引)。然后从任何源浏览可能的目的地,并将任何已看到的目的地存储在一个集合中。一旦看到一个新的目的地,就会有一个循环 Python代码可以是:
def build_dict(lst):
d = dict()
for src, dst in lst:
if src not in d:
d[src] = []
d[src].append(dst)
return d
def dict_loops(d, start=None, seen=None):
if start is None:
return any(dict_loops(d, elt, None) for elt in d.keys())
if start not in d:
return False
if seen is None:
seen = {start}
for hop in d[start]:
if hop in seen:
return True
if dict_loops(d, hop, seen):
return True
return False
def lst_loops(lst):
return dict_loops(build_dict(lst))
正如预期的那样:
>>> lst_loops([(1,2), (3,4), (2,3)])
False
>>> lst_loops([(1,2), (3,4), (2,3), (3,1)])
True
>>>
表示第一个列表中没有循环,第二个列表中至少有一个循环。您可以使用递归生成器函数:
def no_cycles(graph):
def has_cycles(n, s = []):
if n in s:
yield (False, n)
else:
yield (True, n)
yield from [i for a, b in graph for i in has_cycles(b, s+[n]) if a == n]
return all(a for a, _ in has_cycles(graph[0][0]))
graphs = [[(1, 2)], [(1, 2), (2, 3)], [(1, 2), (3, 4), (2, 3)], [(1, 2), (3, 4), (2, 3), (3, 1)], [(5, 6), (5, 7), (5, 8), (5, 9), (9, 10), (10, 5)], [(5, 6), (5, 7), (5, 8), (5, 9), (9, 10), (10, 15)]]
result = [no_cycles(i) for i in graphs]
输出:
[True, True, True, False, False, True]
你试过什么?你需要构建一个图(这只是一个字典),然后你需要做一个深度优先树遍历,看看你是否回到以前访问过的节点。用计算机科学的术语来说,你试图证明你的“有向图”是一个“有向无环图”。
[True, True, True, False, False, True]