【问题标题】:A* Search - least number of hops?A* 搜索 - 跳数最少?
【发布时间】:2013-03-28 23:55:12
【问题描述】:

我正在尝试创建一个 A* 寻路算法,但是我在开始使用它时遇到了一些麻烦。一点背景:

我并不精通寻路算法,但几年前我确实接触过这个主题(我已经忘记了我所学到的一切)。我玩 EVE Online,这是一个关于互联网宇宙飞船的在线游戏。开发人员发布静态信息(游戏中的项目、太阳系位置等)的数据转储。我正在尝试找到从太阳系 A 到太阳系 B 的最短路线。

看看这张地图:http://evemaps.dotlan.net/map/UUA-F4 那是游戏中的一个区域,每个节点都是一个系统。我想计算其中任意两个系统之间的最短距离。

我的问题:我在网上读到的关于 A* 的所有内容都在谈论合并两个节点之间的距离(例如,两个城市之间的距离)以帮助计算最短路径。这对我的情况没有帮助,因为我对跃点数(节点 1 > 节点 2 > 节点 3)而不是这些跃点之间的距离更感兴趣。我不知道如何修改 A* 算法来合并它。

我在数据库中的信息: 所有系统及其邻居的列表(因此,systemX 与 systemA 和 systemB 链接) 3D 网格中所有系统的 x、y 和 z 坐标

如果有人能指出我正确的方向,那就太好了。我希望在 PHP 中使用它,但是我也开始在 Python 中工作一点,所以它也可以工作。

如有需要,可应要求提供示例数据。

编辑

正如一些人所指出的,与每次跳跃相关的“成本”只是 1。但是,对于 A*,您还需要一个启发式方法来估计从当前节点到目标节点的距离。我不确定如何确定这个值,因为我不确定剩余的跃点。如前所述,我确实有每个节点的 3D 坐标 (x,y,z),但我不确定这是否可以提供任何见解,因为每个节点之间的物理距离无关紧要。我知道没有任何路径跨越超过 99 跳。

编辑 2

示例区域的 MySQL 数据。

to -> from 数据:http://pastebin.com/gTuwdr7h

系统信息(x,y,z 坐标,如果需要):http://pastebin.com/Vz3FD3Kz

【问题讨论】:

  • 如果两个节点之间的距离始终为 1(一跳),则只需将每条路径的成本设为 1 并在图上运行 A*。
  • 可能发布示例数据...

标签: php python path-finding a-star


【解决方案1】:

如果“跳数”对您来说很重要,那么将其视为您的距离,这意味着如果两个位置通过单跳连接,则距离为一。

对于 A*,您需要两件事:

  1. 从一个位置到每个邻居的成本,在您的情况下,这似乎是恒定的(跳跃)。

  2. 一种启发式方法,用于估计从当前“节点”或位置到目标的成本。如何估计这在很大程度上取决于您的问题。重要的是,您的启发式算法不会*高*估计真实成本,否则 A* 将无法保证最佳结果。

【讨论】:

  • 虽然很难定义启发式算法。如果填写 0 或 1,则最终会使用 Dijkstra 算法。
  • flup,我认为这是我感到困惑的事情之一。如果所有节点之间的距离为 1,我该如何使用 A*?我可以使用 2 作为启发式方法吗?这有点超出我的想象,但算法显然会在进入搜索循环之前检查两个节点是否相同或邻居,因此“2”是 A* 必须处理的最小距离......跨度>
  • 使用 2 与使用 0 作为启发式基本相同,因为它是恒定的,它不会帮助您的算法更快地执行。启发式的目标是提供一个近似值,允许 A* 选择一条它预测可以更快到达目标的路径。
【解决方案2】:

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

【讨论】:

  • 感谢您花时间实际手动复制该图像的一部分以作为工作示例。赞!但是,我仍然对如何确定启发式方法感到困惑。由于每一跳 (g) 的成本为 1,而且我无法估算 h,那么确定这一点的最佳方法是什么?
  • 这里的算法是Dijkstra's algorithm,它类似于A* 也许只是像here一样将启发式设置为0?
  • 这是我的想法。 h=0 的 A* 仍然是 Dijkstra。也许A *可能不是我当时正在寻找的东西,因此我很难掌握它。因为我不是在寻找节点之间的距离,所以只有最少的跳数,也许 Dijkstra 和 A* 不是我想要的。也许 BFS 代替......
猜你喜欢
  • 1970-01-01
  • 2013-03-07
  • 2017-09-24
  • 2012-02-06
  • 2016-10-23
  • 1970-01-01
  • 2021-02-11
  • 2016-03-18
  • 1970-01-01
相关资源
最近更新 更多