我正在尝试创建一个A*寻路算法,但是我有一个小麻烦与它脱离地面。一点背景:
我绝不精通寻路算法,但几年前我确实谈到过这个问题(我已经忘记了我学到的一切)。我在网上玩EVE,这是一个关于互联网宇宙飞船的在线游戏。开发人员发布静态信息(游戏中的项目、太阳系位置等)的数据转储。我正在寻找从太阳系A到太阳系B的最短路线。
看看这个地图:http://evemaps.dotlan.net/map/UUA-F4这是游戏中的一个区域,每个节点都是一个系统。我想计算这两个系统之间的最短距离。
我的问题:我在网上读到的关于A*的所有内容都是关于合并两个节点之间的距离(例如,两个城市之间的距离)来帮助计算最短路径。这对我的情况没有帮助,因为我更感兴趣的是跳数(node 1>node 2>node 3),而不是那些跳之间的距离。我不知道如何修改A*算法来合并这个。
数据库中的信息:
所有系统及其邻居的列表(因此,systemX与systemA和systemB链接)
三维网格中所有系统的x、y和z坐标
如果有人能给我指出正确的方向,那就太好了。我希望在PHP中使用它,但是我也开始在Python中工作了一些,这样也可以工作。
如有需要,可根据要求提供示例数据。
编辑
正如一些人指出的那样,每次跳跃的“成本”将是1。但是,使用*时,还需要一个启发式算法来估计从当前节点到目标节点的距离。我不确定如何确定这个值,因为我不确定剩余的跳数。如前所述,我确实有每个节点的三维坐标(x,y,z),但我不确定这是否能提供任何洞察,因为每个节点之间的物理距离并不重要。我知道没有一条路能超过99跳。
编辑2
示例区域的MySQL数据。to -> from
数据:http://pastebin.com/gTuwdr7h
系统信息(如果需要,x、y、z坐标):http://pastebin.com/Vz3FD3Kz
最佳答案
取linked graph的上部:
假设这些线表示2个方向(即,您可以进入或离开任何链接节点),黑线是1的“成本”,红线是2的“成本”。
该结构可以由以下Python数据结构表示:
graph = {'Q-KCK3': {'3C-261':1, 'L-SDU7':1},
'L-SDU7': {'Q-KCK3':1, '3C-261':1,'4-IPWK':1},
'3C-261': {'4-IPWK':1,'9K-VDI':1,'L-SDU7':1,'U8MM-3':1},
'U8MM-3': {'9K-VDI':1,'3C-261':1, '9K-VDI':1, 'Q8T-MC':2},
'Q8T-MC': {'U8MM-3':2, 'H55-2R':1, 'VM-QFU':2},
'H55-2R': {'Q8T-MC':1, '9XI-OX':1, 'A3-PAT':1, 'P6-DBM':1},
'P6-DBM': {'A3-PAT':1, 'H55-2R':1},
'A3-PAT': {'P6-DBM':1, 'H55-2R':1, '9XI-OX':1,'YRZ-E4':1},
'YRZ-E4': {'A3-PAT':1},
'VM-QFU': {'IEZW-V':1, 'PU-128':2},
'IEZW-V': {'VM-QFU':1, 'PU-128':1, 'B-DX09':1},
'PU-128': {'VM-QFU':1, 'B-DX09':1, 'IEZW-V':1},
'B-DX09': {'IEZW-V':1, 'PU-128':1, '1TS-WIN':1},
'1TS-WIN': {'B-DX09':1, '16-31U':1},
'16-31U': {'1TS-WIN':1}
}
现在,您可以定义一个递归函数来导航该数据:
def find_all_paths(graph, start, end, path=[]):
path = path + [start]
if start == end:
return [path]
if start not in graph:
return []
paths = []
for node in graph[start]:
if node not in path:
newpaths = find_all_paths(graph, node, end, path)
for newpath in newpaths:
paths.append(newpath)
return paths
def min_path(graph, start, end):
paths=find_all_paths(graph,start,end)
mt=10**99
mpath=[]
print '\tAll paths:',paths
for path in paths:
t=sum(graph[i][j] for i,j in zip(path,path[1::]))
print '\t\tevaluating:',path, t
if t<mt:
mt=t
mpath=path
e1='\n'.join('{}->{}:{}'.format(i,j,graph[i][j]) for i,j in zip(mpath,mpath[1::]))
e2=str(sum(graph[i][j] for i,j in zip(mpath,mpath[1::])))
print 'Best path: '+e1+' Total: '+e2+'\n'
现在演示:
min_path(graph,'Q-KCK3','A3-PAT')
min_path(graph,'Q-KCK3','16-31U')
印刷品:
All paths: [['Q-KCK3', '3C-261', 'U8MM-3', 'Q8T-MC', 'H55-2R', 'P6-DBM', 'A3-PAT'], ['Q-KCK3', '3C-261', 'U8MM-3', 'Q8T-MC', 'H55-2R', 'A3-PAT'], ['Q-KCK3', 'L-SDU7', '3C-261', 'U8MM-3', 'Q8T-MC', 'H55-2R', 'P6-DBM', 'A3-PAT'], ['Q-KCK3', 'L-SDU7', '3C-261', 'U8MM-3', 'Q8T-MC', 'H55-2R', 'A3-PAT']]
evaluating: ['Q-KCK3', '3C-261', 'U8MM-3', 'Q8T-MC', 'H55-2R', 'P6-DBM', 'A3-PAT'] 7
evaluating: ['Q-KCK3', '3C-261', 'U8MM-3', 'Q8T-MC', 'H55-2R', 'A3-PAT'] 6
evaluating: ['Q-KCK3', 'L-SDU7', '3C-261', 'U8MM-3', 'Q8T-MC', 'H55-2R', 'P6-DBM', 'A3-PAT'] 8
evaluating: ['Q-KCK3', 'L-SDU7', '3C-261', 'U8MM-3', 'Q8T-MC', 'H55-2R', 'A3-PAT'] 7
Best path: Q-KCK3->3C-261:1
3C-261->U8MM-3:1
U8MM-3->Q8T-MC:2
Q8T-MC->H55-2R:1
H55-2R->A3-PAT:1 Total: 6
All paths: [['Q-KCK3', '3C-261', 'U8MM-3', 'Q8T-MC', 'VM-QFU', 'IEZW-V', 'B-DX09', '1TS-WIN', '16-31U'], ['Q-KCK3', '3C-261', 'U8MM-3', 'Q8T-MC', 'VM-QFU', 'IEZW-V', 'PU-128', 'B-DX09', '1TS-WIN', '16-31U'], ['Q-KCK3', '3C-261', 'U8MM-3', 'Q8T-MC', 'VM-QFU', 'PU-128', 'B-DX09', '1TS-WIN', '16-31U'], ['Q-KCK3', '3C-261', 'U8MM-3', 'Q8T-MC', 'VM-QFU', 'PU-128', 'IEZW-V', 'B-DX09', '1TS-WIN', '16-31U'], ['Q-KCK3', 'L-SDU7', '3C-261', 'U8MM-3', 'Q8T-MC', 'VM-QFU', 'IEZW-V', 'B-DX09', '1TS-WIN', '16-31U'], ['Q-KCK3', 'L-SDU7', '3C-261', 'U8MM-3', 'Q8T-MC', 'VM-QFU', 'IEZW-V', 'PU-128', 'B-DX09', '1TS-WIN', '16-31U'], ['Q-KCK3', 'L-SDU7', '3C-261', 'U8MM-3', 'Q8T-MC', 'VM-QFU', 'PU-128', 'B-DX09', '1TS-WIN', '16-31U'], ['Q-KCK3', 'L-SDU7', '3C-261', 'U8MM-3', 'Q8T-MC', 'VM-QFU', 'PU-128', 'IEZW-V', 'B-DX09', '1TS-WIN', '16-31U']]
evaluating: ['Q-KCK3', '3C-261', 'U8MM-3', 'Q8T-MC', 'VM-QFU', 'IEZW-V', 'B-DX09', '1TS-WIN', '16-31U'] 10
evaluating: ['Q-KCK3', '3C-261', 'U8MM-3', 'Q8T-MC', 'VM-QFU', 'IEZW-V', 'PU-128', 'B-DX09', '1TS-WIN', '16-31U'] 11
evaluating: ['Q-KCK3', '3C-261', 'U8MM-3', 'Q8T-MC', 'VM-QFU', 'PU-128', 'B-DX09', '1TS-WIN', '16-31U'] 11
evaluating: ['Q-KCK3', '3C-261', 'U8MM-3', 'Q8T-MC', 'VM-QFU', 'PU-128', 'IEZW-V', 'B-DX09', '1TS-WIN', '16-31U'] 12
evaluating: ['Q-KCK3', 'L-SDU7', '3C-261', 'U8MM-3', 'Q8T-MC', 'VM-QFU', 'IEZW-V', 'B-DX09', '1TS-WIN', '16-31U'] 11
evaluating: ['Q-KCK3', 'L-SDU7', '3C-261', 'U8MM-3', 'Q8T-MC', 'VM-QFU', 'IEZW-V', 'PU-128', 'B-DX09', '1TS-WIN', '16-31U'] 12
evaluating: ['Q-KCK3', 'L-SDU7', '3C-261', 'U8MM-3', 'Q8T-MC', 'VM-QFU', 'PU-128', 'B-DX09', '1TS-WIN', '16-31U'] 12
evaluating: ['Q-KCK3', 'L-SDU7', '3C-261', 'U8MM-3', 'Q8T-MC', 'VM-QFU', 'PU-128', 'IEZW-V', 'B-DX09', '1TS-WIN', '16-31U'] 13
Best path: Q-KCK3->3C-261:1
3C-261->U8MM-3:1
U8MM-3->Q8T-MC:2
Q8T-MC->VM-QFU:2
VM-QFU->IEZW-V:1
IEZW-V->B-DX09:1
B-DX09->1TS-WIN:1
1TS-WIN->16-31U:1 Total: 10
如果您想要最小跳数,只需修改
min_path
以返回最短的列表长度,而不是跳的最小总开销。或者,使每个跳的成本1
。看看my previous answer regarding trains。