在图中找到最长的路径
finding longest path in a graph
我正在尝试解决一个程序,其中我必须找到给定路线列表连接的最大城市数。
例如:
如果给定的路线是 [['1', '2'], ['2', '4'], ['1', '11'], ['4', '11']]
那么连接的最大城市数将为 4
限制是我不能访问我已经访问过的城市。
我需要想法,比如如何进步。
目前,我的想法是,如果我能够创建一个以城市为键的字典,以及它连接到多少个其他城市作为它的值,我就接近解决方案了(我希望) .
例如:我的字典将是 {'1': ['2', '11'], '4': ['11'], '2': ['4']}
对于上面给定的输入。
如果我遗漏了什么,我需要帮助和指导。
您可以使用 defaultdict
从 edges/paths 的列表中创建您的 "Graph":
edges = [['1', '2'], ['2', '4'], ['1', '11'], ['4', '11']]
G = defaultdict(list)
for (s,t) in edges:
G[s].append(t)
G[t].append(s)
print G.items()
输出:
[
('1', ['2', '11']),
('11', ['1', '4']),
('2', ['1', '4']),
('4', ['2', '11'])
]
请注意,我在两个方向上都添加了边,因为您使用的是无向图。因此对于边 (a,b),G[a]
将包含 b
并且 G[b]
将包含 a
.
据此,您可以使用类似 depth-first search or breadth-first search 的算法来发现图中的所有路径。
在下面的代码中,我使用了 DFS:
def DFS(G,v,seen=None,path=None):
if seen is None: seen = []
if path is None: path = [v]
seen.append(v)
paths = []
for t in G[v]:
if t not in seen:
t_path = path + [t]
paths.append(tuple(t_path))
paths.extend(DFS(G, t, seen[:], t_path))
return paths
你可以使用:
G = defaultdict(list)
for (s,t) in edges:
G[s].append(t)
G[t].append(s)
print DFS(G, '1')
输出:
[('1', '2'), ('1', '2', '4'), ('1', '2', '4', '11'), ('1', '11'), ('1', '11', '4'), ('1', '11', '4', '2')]
完整代码,最后一位显示最长路径:
from collections import defaultdict
def DFS(G,v,seen=None,path=None):
if seen is None: seen = []
if path is None: path = [v]
seen.append(v)
paths = []
for t in G[v]:
if t not in seen:
t_path = path + [t]
paths.append(tuple(t_path))
paths.extend(DFS(G, t, seen[:], t_path))
return paths
# Define graph by edges
edges = [['1', '2'], ['2', '4'], ['1', '11'], ['4', '11']]
# Build graph dictionary
G = defaultdict(list)
for (s,t) in edges:
G[s].append(t)
G[t].append(s)
# Run DFS, compute metrics
all_paths = DFS(G, '1')
max_len = max(len(p) for p in all_paths)
max_paths = [p for p in all_paths if len(p) == max_len]
# Output
print("All Paths:")
print(all_paths)
print("Longest Paths:")
for p in max_paths: print(" ", p)
print("Longest Path Length:")
print(max_len)
输出:
All Paths:
[('1', '2'), ('1', '2', '4'), ('1', '2', '4', '11'), ('1', '11'), ('1', '11', '4'), ('1', '11', '4', '2')]
Longest Paths:
('1', '2', '4', '11')
('1', '11', '4', '2')
Longest Path Length:
4
请注意,您搜索的 "starting point" 由 DFS
函数的第二个参数指定,在本例中为 '1'
。
更新: 正如评论中所讨论的那样,上面的代码假设您有一个起点(具体来说,代码使用标记为 '1'
的节点)。
一个更通用的方法,在你没有这样的起点的情况下,是从每个节点开始执行搜索,并取最长的。
(注意:实际上,你可以比这更聪明)
换行
all_paths = DFS(G, '1')
至
all_paths = [p for ps in [DFS(G, n) for n in set(G)] for p in ps]
会给你 任意 两点之间的最长路径。
(这是一个愚蠢的列表理解,但它允许我只更新一行。更清楚地说,它等同于以下内容:
all_paths = []
for node in set(G.keys()):
for path in DFS(G, node):
all_paths.append(path)
或
from itertools import chain
all_paths = list(chain.from_iterable(DFS(G, n) for n in set(G)))
).
这是我的代码,适用于示例中的输入,但如果我稍微调整输入,代码将无法给出正确的连接城市数。
def dfs(graph, start, visited=None):
if visited is None:
visited = set()
visited.add(start)
#had to do this for the key error that i was getting if the start doesn't
#have any val.
if isinstance(start,str) and start not in graph.keys():
pass
else:
for next in set(graph[start]) - visited:
dfs(graph, next, visited)
return visited
def maxno_city(input1):
totalcities = []
max_nocity = 0
routedic = {}
#dup = []
rou = []
for cities in input1:
cities = cities.split('#')
totalcities.append(cities)
print (totalcities)
for i in totalcities:
if i[0] in routedic.keys():
routedic[i[0]].append(i[1])
else:
routedic.update({i[0]:[i[1]]})
print(routedic)
keys = routedic.keys()
newkeys = []
for i in keys:
newkeys.append(i)
print (newkeys)
newkeys.sort()
print (newkeys)
expath = dfs(routedic,newkeys[0])
return(len(expath))
上面给定输入的输出是 4
我得到 4
但如果输入更改为如下所示:
['1#2','2#3','1#11','3#11','4#11','4#5','5#6','5#7','6#7','4#12','8#12','9#12','8#10','9#10',8#9]
我的代码失败了。
谢谢,
学习忍者 :D
我正在尝试解决一个程序,其中我必须找到给定路线列表连接的最大城市数。
例如:
如果给定的路线是 [['1', '2'], ['2', '4'], ['1', '11'], ['4', '11']]
那么连接的最大城市数将为 4
限制是我不能访问我已经访问过的城市。
我需要想法,比如如何进步。
目前,我的想法是,如果我能够创建一个以城市为键的字典,以及它连接到多少个其他城市作为它的值,我就接近解决方案了(我希望) .
例如:我的字典将是 {'1': ['2', '11'], '4': ['11'], '2': ['4']}
对于上面给定的输入。
如果我遗漏了什么,我需要帮助和指导。
您可以使用 defaultdict
从 edges/paths 的列表中创建您的 "Graph":
edges = [['1', '2'], ['2', '4'], ['1', '11'], ['4', '11']]
G = defaultdict(list)
for (s,t) in edges:
G[s].append(t)
G[t].append(s)
print G.items()
输出:
[ ('1', ['2', '11']), ('11', ['1', '4']), ('2', ['1', '4']), ('4', ['2', '11']) ]
请注意,我在两个方向上都添加了边,因为您使用的是无向图。因此对于边 (a,b),G[a]
将包含 b
并且 G[b]
将包含 a
.
据此,您可以使用类似 depth-first search or breadth-first search 的算法来发现图中的所有路径。
在下面的代码中,我使用了 DFS:
def DFS(G,v,seen=None,path=None):
if seen is None: seen = []
if path is None: path = [v]
seen.append(v)
paths = []
for t in G[v]:
if t not in seen:
t_path = path + [t]
paths.append(tuple(t_path))
paths.extend(DFS(G, t, seen[:], t_path))
return paths
你可以使用:
G = defaultdict(list)
for (s,t) in edges:
G[s].append(t)
G[t].append(s)
print DFS(G, '1')
输出:
[('1', '2'), ('1', '2', '4'), ('1', '2', '4', '11'), ('1', '11'), ('1', '11', '4'), ('1', '11', '4', '2')]
完整代码,最后一位显示最长路径:
from collections import defaultdict
def DFS(G,v,seen=None,path=None):
if seen is None: seen = []
if path is None: path = [v]
seen.append(v)
paths = []
for t in G[v]:
if t not in seen:
t_path = path + [t]
paths.append(tuple(t_path))
paths.extend(DFS(G, t, seen[:], t_path))
return paths
# Define graph by edges
edges = [['1', '2'], ['2', '4'], ['1', '11'], ['4', '11']]
# Build graph dictionary
G = defaultdict(list)
for (s,t) in edges:
G[s].append(t)
G[t].append(s)
# Run DFS, compute metrics
all_paths = DFS(G, '1')
max_len = max(len(p) for p in all_paths)
max_paths = [p for p in all_paths if len(p) == max_len]
# Output
print("All Paths:")
print(all_paths)
print("Longest Paths:")
for p in max_paths: print(" ", p)
print("Longest Path Length:")
print(max_len)
输出:
All Paths: [('1', '2'), ('1', '2', '4'), ('1', '2', '4', '11'), ('1', '11'), ('1', '11', '4'), ('1', '11', '4', '2')] Longest Paths: ('1', '2', '4', '11') ('1', '11', '4', '2') Longest Path Length: 4
请注意,您搜索的 "starting point" 由 DFS
函数的第二个参数指定,在本例中为 '1'
。
更新: 正如评论中所讨论的那样,上面的代码假设您有一个起点(具体来说,代码使用标记为 '1'
的节点)。
一个更通用的方法,在你没有这样的起点的情况下,是从每个节点开始执行搜索,并取最长的。 (注意:实际上,你可以比这更聪明)
换行
all_paths = DFS(G, '1')
至
all_paths = [p for ps in [DFS(G, n) for n in set(G)] for p in ps]
会给你 任意 两点之间的最长路径。
(这是一个愚蠢的列表理解,但它允许我只更新一行。更清楚地说,它等同于以下内容:
all_paths = []
for node in set(G.keys()):
for path in DFS(G, node):
all_paths.append(path)
或
from itertools import chain
all_paths = list(chain.from_iterable(DFS(G, n) for n in set(G)))
).
这是我的代码,适用于示例中的输入,但如果我稍微调整输入,代码将无法给出正确的连接城市数。
def dfs(graph, start, visited=None):
if visited is None:
visited = set()
visited.add(start)
#had to do this for the key error that i was getting if the start doesn't
#have any val.
if isinstance(start,str) and start not in graph.keys():
pass
else:
for next in set(graph[start]) - visited:
dfs(graph, next, visited)
return visited
def maxno_city(input1):
totalcities = []
max_nocity = 0
routedic = {}
#dup = []
rou = []
for cities in input1:
cities = cities.split('#')
totalcities.append(cities)
print (totalcities)
for i in totalcities:
if i[0] in routedic.keys():
routedic[i[0]].append(i[1])
else:
routedic.update({i[0]:[i[1]]})
print(routedic)
keys = routedic.keys()
newkeys = []
for i in keys:
newkeys.append(i)
print (newkeys)
newkeys.sort()
print (newkeys)
expath = dfs(routedic,newkeys[0])
return(len(expath))
上面给定输入的输出是 4
我得到 4
但如果输入更改为如下所示:
['1#2','2#3','1#11','3#11','4#11','4#5','5#6','5#7','6#7','4#12','8#12','9#12','8#10','9#10',8#9]
我的代码失败了。
谢谢, 学习忍者 :D