问题描述
我想将地图转换为图形/相邻列表/相邻矩阵。
例如,假设我有一张地图,@ 标记代表无法进入的墙壁,数字代表节点:
@@@@@@@
@12 5@
@@@3@@@
@4 @
@@@@@@@
节点坐标:
1: (1,3)
2: (2,3)
3: (3,2)
4: (1,1)
5: (5,3)
这个问题的输出应该是这样的图:
1-2-5
\ /
3
|
4
1 只能连接到 2,因为 2 是 1 可以在不经过其他节点的情况下到达的唯一节点。 2可以连接1、3、5,原因同上。
给出了墙和节点坐标。我想要一种算法将任何给定的地图转换为像上面那样的图形。任何人都可以提出解决方案吗?
解决方法
您可以使用递归查找地图中数字之间的连接,即使它们彼此不直接相邻:
from functools import reduce as rd
s = """
@@@@@@@
@12 5@
@@@3@@@
@4 @
@@@@@@@
"""
#convert the map to a coordinate dictionary
coords = {(k,j):b for j,a in enumerate(filter(None,s.split('\n'))) for k,b in enumerate(a)}
def to_graph(start,seen = []):
t_coords = [lambda x,y:(x+1,y),lambda x,y+1),y:(x,y:(x-1,y-1),y-1)]
#find possible valid squares to consume
if (ops:=[k for f in t_coords if (k:=(f(*start))) in coords and coords[k] != '@']):
#recursively check possible squares
results = [to_graph(i,seen+[start]) for i in ops if i not in seen]
vals = rd(lambda x,y:{**x,**y},results,{}) #merge results
return {coords[start]:vals} if coords[start].isdigit() else vals
print(to_graph((1,1))) #start with coordinates of any value
输出:
{'1': {'2': {'5': {},'3': {'4': {},'5': {}}}}}
输出返回一个字典,显示地图中定位的值之间的关系:1 -> 2,2 -> (5,3),3 -> (4,5)
这是另一种解决方案,即使某些节点与其他节点根本没有连接,它也能工作,并且内存成本更低:
def getNodes(l):
a={}
for i in range(len(l)):
for j in range(len(l[i])):
if (type(l[i][j]) is type(1)):
a.update({l[i][j]:(i,j)})
return a
def searchAdjascentNodes(m,coordonates):
nodes=set()
old=set()
toDo=set([coordonates])
while (len(toDo)!=0):
discoveredVertices=[]
for i in toDo:
adjascent=[j for j in [(i[0],i[1]+1),(i[0],i[1]-1),(i[0]+1,i[1]),(i[0]-1,i[1])] if (j[0]>=0 and j[0]<len(m) and j[1]>=0 and j[1]<len(m[0]) and j not in old and j not in toDo and j not in discoveredVertices)]
for a in adjascent:
if(type(m[a[0]][a[1]]) is int):
nodes.add(m[a[0]][a[1]])
elif(m[a[0]][a[1]]==' '):
discoveredVertices.append(a)
old=toDo.copy()
toDo=set(discoveredVertices)
return nodes
def createGraph(m):
n=getNodes(m)
r={}
for i in n:
r.update({i:searchAdjascentNodes(m,n[i])})
return r
你可以这样运行:
theMap=[['@','@','@'],['@',1,2,' ',5,3,4,'@']]
print(createGraph(theMap))
你会得到:
{1: {2},2: {1,5},5: {2,3},3: {2,4: {3}}