继How to speed up least-cost path model at large spatial extents后,我尝试在Netlogo中编写A *算法,以便在大空间范围内增加最低成本路径模型。这是我的代码:
to findPath [ID-start-node ID-end-node]
let currentNodesInList [ ]
let current-node node ID-start-node
let end-node node ID-end-node
ask current-node [ set color red]
ask end-node [ set color red]
set currentNodesInList lput current-node currentNodesInList
while [not member? end-node currentNodesInList] [
ask current-node [
foreach sort nodes-on neighbors [
ask ? [set f-value [link-cost] of link ([who] of current-node) ([who] of ?) + distance end-node] ]
let next-current-node min-one-of [nodes-on neighbors] of current-node [f-value]
ask link ([who] of current-node) ([who] of next-current-node) [set color red]
set current-node next-current-node
set currentNodesInList lput current-node currentNodesInList] ]
end
当ID-start-node和ID-end-node在景观中关闭时,代码似乎有效。但是,当ID-start-node和ID-end-node之间的距离较大时,路径不会到达ID-end-node(见下图;但有时,代码可以工作)。
在图中,ID-start-node和ID-end-node用红色开头表示,路径用红色表示。
非常感谢你的帮助。
答案 0 :(得分:5)
您可能希望在NetLogo用户社区中查看此模型:
http://ccl.northwestern.edu/netlogo/models/community/Astardemo1
它实现了一个简单的过程(find-a-path),它将源补丁和目标补丁作为参数,并返回一个补丁列表(这是从源补丁到目标补丁的最短路径之一) A星最短路径寻找算法。
您也可以尝试关闭世界包装。
答案 1 :(得分:3)
A *必须有一种方法来备份尝试旧路径,如果它遇到了一个deadend,或者看起来效率低下的东西。您的实现只是在一条路上继续前进。虽然你的方式绝对是实现路径查找的最自然的方式,而且更简单,这可能就是你遇到问题的原因。
这是我想出的一个实现。它直接使用补丁而不是链接,实际上它似乎对你更好。只需给它一个补丁任务,报告跨该补丁和源和目标补丁的旅行成本。我对此并不满意:真正的A *使用堆来跟踪每个可能的路径应该有多好。我不得不用列表模拟堆,因此它不会像真正的A *那样快。如果其他人看到了改进,请随时编辑我的答案或在评论中提出建议!无论如何,这是:
to-report find-path [ get-cost source destination ]
let paths (list (list source))
let estimated-costs (list [distance destination ] of source)
let path first paths
let visited patch-set source
let encountered patch-set source
while [ source != destination ] [
let estimated-cost min estimated-costs
let path-index position estimated-cost estimated-costs
set path item path-index paths
set source last path
let path-cost estimated-cost - [ distance destination ] of source
let source-cost [ runresult get-cost ] of source
set paths remove-item path-index paths
set estimated-costs remove-item path-index estimated-costs
set visited (patch-set source visited)
ask [ neighbors with [ not member? self visited ] ] of source [
let patch-cost runresult get-cost
let step-cost distance source * (patch-cost + source-cost) / 2
let est-cost path-cost + step-cost + distance destination
let add? true
if member? self encountered [
let other-path false
foreach paths [
if last ? = self [
set other-path ?
]
]
if other-path != false [
let other-path-index position other-path paths
let other-path-cost item other-path-index estimated-costs
ifelse other-path-cost < est-cost [
set add? false
] [
set paths remove-item other-path-index paths
set estimated-costs remove-item other-path-index estimated-costs
]
]
]
if add? [
set estimated-costs fput est-cost estimated-costs
set paths fput (lput self path) paths
set encountered (patch-set self encountered)
]
]
]
report path
end
如果cost
是一个补丁变量,其中包含穿过该补丁的费用,那么您可以这样称呼它:find-path task [ cost ] source-patch target-patch
。希望这有帮助!