導航:首頁 > 源碼編譯 > 開放世界尋路演算法

開放世界尋路演算法

發布時間:2023-12-08 23:30:00

㈠ 從原點出發,遍歷50個點,再回到原點的最短路徑,求matlab程序

據 Drew 所知最短路經演算法現在重要的應用有計算機網路路由演算法,機器人探路,交通路線導航,人工智慧,游戲設計等等。美國火星探測器核心的尋路演算法就是採用的D*(D Star)演算法。

最短路經計算分靜態最短路計算和動態最短路計算。

靜態路徑最短路徑演算法是外界環境不變,計算最短路徑。主要有Dijkstra演算法,A*(A Star)演算法。

動態路徑最短路是外界環境不斷發生變化,即不能計算預測的情況下計算最短路。如在游戲中敵人或障礙物不斷移動的情況下。典型的有D*演算法。這是Drew程序實現的10000個節點的隨機路網三條互不相交最短路真實路網計算K條路徑示例:節點5696到節點3006,三條最快速路,可以看出路徑基本上走環線或主幹路。黑線為第一條,蘭線為第二條,紅線為第三條。約束條件系數為1.2。共享部分路段。 顯示計算部分完全由Drew自己開發的程序完成。 參見 K條路演算法測試程序

Dijkstra演算法求最短路徑:

Dijkstra演算法是典型最短路演算法,用於計算一個節點到其他所有節點的最短路徑。主要特點是以起始點為中心向外層層擴展,直到擴展到終點為止。Dijkstra演算法能得出最短路徑的最優解,但由於它遍歷計算的節點很多,所以效率低。

Dijkstra演算法是很有代表性的最短路演算法,在很多專業課程中都作為基本內容有詳細的介紹,如數據結構,圖論,運籌學等等。

Dijkstra一般的表述通常有兩種方式,一種用永久和臨時標號方式,一種是用OPEN, CLOSE表方式,Drew為了和下面要介紹的 A* 演算法和 D* 演算法表述一致,這里均採用OPEN,CLOSE表的方式。

大概過程:
創建兩個表,OPEN, CLOSE。
OPEN表保存所有已生成而未考察的節點,CLOSED表中記錄已訪問過的節點。
1. 訪問路網中里起始點最近且沒有被檢查過的點,把這個點放入OPEN組中等待檢查。
2. 從OPEN表中找出距起始點最近的點,找出這個點的所有子節點,把這個點放到CLOSE表中。
3. 遍歷考察這個點的子節點。求出這些子節點距起始點的距離值,放子節點到OPEN表中。
4. 重復2,3,步。直到OPEN表為空,或找到目標點。

這是在drew 程序中4000個節點的隨機路網上Dijkstra演算法搜索最短路的演示,黑色圓圈表示經過遍歷計算過的點由圖中可以看到Dijkstra演算法從起始點開始向周圍層層計算擴展,在計算大量節點後,到達目標點。所以速度慢效率低。

提高Dijkstra搜索速度的方法很多,據Drew所知,常用的有數據結構採用Binary heap的方法,和用Dijkstra從起始點和終點同時搜索的方法。

推薦網頁:http://www.cs.ecnu.e.cn/assist/js04/ZJS045/ZJS04505/zjs045050a.htm

簡明扼要介紹Dijkstra演算法,有圖解顯示和源碼下載。

A*(A Star)演算法:啟發式(heuristic)演算法

A*(A-Star)演算法是一種靜態路網中求解最短路最有效的方法。

公式表示為: f(n)=g(n)+h(n),
其中f(n) 是節點n從初始點到目標點的估價函數,
g(n) 是在狀態空間中從初始節點到n節點的實際代價,
h(n)是從n到目標節點最佳路徑的估計代價。

保證找到最短路徑(最優解的)條件,關鍵在於估價函數h(n)的選取:
估價值h(n)<= n到目標節點的距離實際值,這種情況下,搜索的點數多,搜索范圍大,效率低。但能得到最優解。
如果 估價值>實際值, 搜索的點數少,搜索范圍小,效率高,但不能保證得到最優解。
估價值與實際值越接近,估價函數取得就越好。
例如對於幾何路網來說,可以取兩節點間歐幾理德距離(直線距離)做為估價值,即f=g(n)+sqrt((dx-nx)*(dx-nx)+(dy-ny)*(dy-ny));這樣估價函數f在g值一定的情況下,會或多或少的受估價值h的制約,節點距目標點近,h值小,f值相對就小,能保證最短路的搜索向終點的方向進行。明顯優於Dijstra演算法的毫無無方向的向四周搜索。

conditions of heuristic
Optimistic (must be less than or equal to the real cost)
As close to the real cost as possible

主要搜索過程:
創建兩個表,OPEN表保存所有已生成而未考察的節點,CLOSED表中記錄已訪問過的節點。
遍歷當前節點的各個節點,將n節點放入CLOSE中,取n節點的子節點X,->算X的估價值->
While(OPEN!=NULL)
{
從OPEN表中取估價值f最小的節點n;
if(n節點==目標節點) break;
else
{
if(X in OPEN) 比較兩個X的估價值f //注意是同一個節點的兩個不同路徑的估價值
if( X的估價值小於OPEN表的估價值 )
更新OPEN表中的估價值; //取最小路徑的估價值

if(X in CLOSE) 比較兩個X的估價值 //注意是同一個節點的兩個不同路徑的估價值
if( X的估價值小於CLOSE表的估價值 )
更新CLOSE表中的估價值; 把X節點放入OPEN //取最小路徑的估價值

if(X not in both)
求X的估價值;
並將X插入OPEN表中;//還沒有排序
}

將n節點插入CLOSE表中;
按照估價值將OPEN表中的節點排序; //實際上是比較OPEN表內節點f的大小,從最小路徑的節點向下進行。
}

㈡ lua語言a星尋路演算法路徑怎麼平滑

在項目中遇到了自動尋路的需求,於是決定開始學習一下A星,對於A星我也沒有深究,只能說是勉強搞定了需求,在這和大家分享一下,相互進步,

A星有個公式 f(x) = g(x) + h(x)
,搞清楚這個公式就好辦了,f(x)就是當前位置到下一個位置的總價值,g(x)表示實際價,這是說這一部分代價是確定的,h(x)表示估價值,就是說我
從下一個位置到到終點的代價是未知的,所以叫估價值,如圖中所示,黑色格子表示當前位置,綠色格子表示下一步可能到達的位置,即上、下、左、右這幾個方
向,紅色格子表示終點,褐色表示障礙物,現在要從黑色格子到達紅色格子,那麼黑色格子的下一步肯定是綠色格子當中的一個,黑色格子到綠色格子之間是相挨著
的,所以我們可以很明確的知道它的實際代價為1(移動一步的代價)即g(x),綠色格子到紅色格子之間隔著很長的距離,中間還有障礙物,所以這個代價是未
知的,即h(x),所以總的代價就為f(x) = g(x) +
h(x),我們看到周圍有4個綠色的格子,到底走那一步比較好呢,所以我們要把這4個格子的f(x)值都求出來,然後進行排序,選擇f(x)值最小的,即
總代價最少的那個格子,以此方法繼續下去,直到到達終點 或者 地圖上沒有綠色格子了

下面來看一下這個工具類,g(x)和h(x)要選的比較合適,一般就是採用的曼哈頓演算法,即兩點在x方向和y方向的距離之和,
-- Filename: PathUtil.lua
-- Author: bzx
-- Date: 2014-07-01
-- Purpose: 尋路

mole("PathUtil", package.seeall)

local _map_data -- 地圖數據
local _open_list -- 開放節點
local _open_map -- 開放節點,為了提高性能而加
local _close_map -- 關閉節點
local _deleget -- 代理
local _dest_point -- 目標點
local _start_point -- 起點
local _path -- 路徑

-- 尋找路徑
--[[
deleget = {
g = function(point1, point2)
-- add your code
-- 返回點point1到點point2的實際代價
end
h = function(point1, point2)
-- add your code
-- 返回點point1到點point2的估算代價
end
getValue = function(j, i)
-- 返回地圖中第i行,第j列的數據 1為障礙物,0為非障礙物
end
width -- 地圖寬度
height -- 地圖高度
}
--]]
function findPath(deleget, start_point, dest_point)
_deleget = deleget
_dest_point = dest_point
_start_point = start_point
init()
while not table.isEmpty(_open_list) do
local cur_point = _open_list[1]
table.remove(_open_list, 1)
_open_map[cur_point.key] = nil
if isEqual(cur_point, dest_point) then
return makePath(cur_point)
else
_close_map[cur_point.key] = cur_point
local next_points = getNextPoints(cur_point)
for i = 1, #next_points do
local next_point = next_points[i]
if _open_map[next_point.key] == nil and _close_map[next_point.key] == nil and isObstacle(next_point) == false then
_open_map[next_point.key] = next_point
table.insert(_open_list, next_point)
end
end
table.sort(_open_list, compareF)
end
end
return nil
end

function init()
_open_list = {}
_open_map = {}
_close_map = {}
_path = {}
_map_data = {}
for i = 1, _deleget.height do
_map_data[i] = {}
for j = 1, _deleget.width do
local value = _deleget.getValue(j, i)
_map_data[i][j] = value
end
end
_open_map[getKey(_start_point)] = _start_point
table.insert(_open_list, _start_point)
end

function createPoint(x, y)
local point = {
["x"] = x,
["y"] = y,
["last"] = nil,
["g_value"] = 0,
["h_value"] = 0,
["f_value"] = 0
}
point["key"] = getKey(point)
return point
end

-- 得到下一個可以移動的點
-- @param point 當前所在點
function getNextPoints(point)
local next_points = {}
for i = 1, #_deleget.directions do
local offset = _deleget.directions[i]
local next_point = createPoint(point.x + offset[1], point.y + offset[2])
next_point["last"] = point
if next_point.x >= 1 and next_point.x <= _deleget.width and next_point.y >= 1 and next_point.y <= _deleget.height then
next_point["g_value"] = _deleget.g(point, next_point)
next_point["h_value"] = _deleget.h(point, _dest_point)--math.abs(next_points.x - _dest_point.x) + math.abs(next_points.y - _dest_point.y)
next_point["f_value"] = next_point.g_value + next_point.h_value
table.insert(next_points, next_point)
end
end
return next_points
end

-- 得到路徑
-- @param end_point 目標點
function makePath(end_point)
_path = {}
local point = end_point
while point.last ~= nil do
table.insert(_path, createPoint(point.x, point.y))
point = point.last
end
local start_point = point
table.insert(_path, start_point)
return _path
end

-- 兩個點的代價比較器
function compareF(point1, point2)
return point1.f_value < point2.f_value
end

-- 是否是障礙物
function isObstacle(point)
local value = _map_data[point.y][point.x]
if value == 1 then
return true
end
return false
end

-- 兩個點是否是同一個點
function isEqual(point1, point2)
return point1.key == point2.key
end

-- 根據點得到點的key
function getKey(point)
local key = string.format("%d,%d", point.x, point.y)
return key
end

下面是工具類PathUtil的用法
local deleget = {}
deleget.g = function(point1, point2)
return math.abs(point1.x - point2.x) + math.abs(point1.y - point2.y)
end
deleget.h = deleget.g
deleget.getValue = function(j, i)
local index = FindTreasureUtil.getIndex(j, i)
local map_info = _map_info.map[index]
if map_info.display == 0 and map_info.eid ~= 1 then
return 0
end
return 1
end
deleget.directions = {{-1, 0}, {0, -1}, {0, 1}, {1, 0}} -- 左,上,下,右
deleget.width = _cols
deleget.height = _rows

local dest_row, dest_col = FindTreasureUtil.getMapPosition(tag)
local dest_point = PathUtil.createPoint(dest_col, dest_row)
local start_row, start_col = FindTreasureUtil.getMapPosition(_player_index)
local start_point = PathUtil.createPoint(start_col, start_row)
_path = PathUtil.findPath(deleget, start_point, dest_point)

_path就是我們找到的路徑,起點為最後一個元素,終點為第一個元素

㈢ 夢幻西遊自動尋路的尋路演算法怎麼算

A*尋路演算法 A*(A-Star)演算法是一種靜態路網中求解最短路最有效的方法。
公式表示為: f(n)=g(n)+h(n),
其中f(n) 是節點n從初始點到目標點的估價函數,
g(n) 是在狀態空間中從初始節點到n節點的實際代價,
h(n)是從n到目標節點最佳路徑的估計代價。
保證找到最短路徑(最優解的)條件,關鍵在於估價函數h(n)的選取:
估價值h(n)<= n到目標節點的距離實際值,這種情況下,搜索的點數多,搜索范圍大,效率低。但能得到最優解。
如果 估價值>實際值, 搜索的點數少,搜索范圍小,效率高,但不能保證得到最優解。
估價值與實際值越接近,估價函數取得就越好。
例如對於幾何路網來說,可以取兩節點間歐幾理德距離(直線距離)做為估價值,即f=g(n)+sqrt((dx-nx)*(dx-nx)+(dy-ny)*(dy-ny));這樣估價函數f在g值一定的情況下,會或多或少的受估價值h的制約,節點距目標點近,h值小,f值相對就小,能保證最短路的搜索向終點的方向進行。明顯優於Dijstra演算法的毫無無方向的向四周搜索。
conditions of heuristic
Optimistic (must be less than or equal to the real cost)
As close to the real cost as possible
主要搜索過程:
創建兩個表,OPEN表保存所有已生成而未考察的節點,CLOSED表中記錄已訪問過的節點。
遍歷當前節點的各個節點,將n節點放入CLOSE中,取n節點的子節點X,->算X的估價值->
While(OPEN!=NULL)
{
從OPEN表中取估價值f最小的節點n;
if(n節點==目標節點) break;
else
{
if(X in OPEN) 比較兩個X的估價值f //注意是同一個節點的兩個不同路徑的估價值
if( X的估價值小於OPEN表的估價值 )
更新OPEN表中的估價值; //取最小路徑的估價值
if(X in CLOSE) 比較兩個X的估價值 //注意是同一個節點的兩個不同路徑的估價值
if( X的估價值小於CLOSE表的估價值 )
更新CLOSE表中的估價值; 把X節點放入OPEN //取最小路徑的估價值
if(X not in both)
求X的估價值;
並將X插入OPEN表中; //還沒有排序
}
將n節點插入CLOSE表中;
按照估價值將OPEN表中的節點排序; //實際上是比較OPEN表內節點f的大小,從最小路徑的節點向下進行。
啟發式搜索其實有很多的演算法,比如:局部擇優搜索法、最好優先搜索法等等。當然A*也是。這些演算法都使用了啟發函數,但在具體的選取最佳搜索節點時的策略不同。象局部擇優搜索法,就是在搜索的過程中選取「最佳節點」後舍棄其他的兄弟節點,父親節點,而一直得搜索下去。這種搜索的結果很明顯,由於舍棄了其他的節點,可能也把最好的
節點都舍棄了,因為求解的最佳節點只是在該階段的最佳並不一定是全局的最佳。最好優先就聰明多了,他在搜索時,便沒有舍棄節點(除非該節點是死節點),在每一步的估價
中都把當前的節點和以前的節點的估價值比較得到一個「最佳的節點」。這樣可以有效的防止「最佳節點」的丟失。那麼A*演算法又是一種什麼樣的演算法呢?其實A*演算法也是一種最
好優先的演算法。只不過要加上一些約束條件罷了。由於在一些問題求解時,我們希望能夠求解出狀態空間搜索的最短路徑,也就是用最快的方法求解問題,A*就是干這種事情的!
我們先下個定義,如果一個估價函數可以找出最短的路徑,我們稱之為可採納性。A*演算法是一個可採納的最好優先演算法。A*演算法的估價函數可表示為:
f'(n) = g'(n) + h'(n)
這里,f'(n)是估價函數,g'(n)是起點到終點的最短路徑值,h'(n)是n到目標的最斷路經的啟發值。由於這個f'(n)其實是無法預先知道的,所以我們用前面的估價函數f(n)做
近似。g(n)代替g'(n),但 g(n)>=g'(n)才可(大多數情況下都是滿足的,可以不用考慮),h(n)代替h'(n),但h(n)<=h'(n)才可(這一點特別的重要)。可以證明應用這樣的估價
函數是可以找到最短路徑的,也就是可採納的。我們說應用這種估價函數的最好優先演算法就是A*演算法。哈。你懂了嗎?肯定沒懂。接著看。
舉一個例子,其實廣度優先演算法就是A*演算法的特例。其中g(n)是節點所在的層數,h(n)=0,這種h(n)肯定小於h'(n),所以由前述可知廣度優先演算法是一種可採納的。實際也是
。當然它是一種最臭的A*演算法。
再說一個問題,就是有關h(n)啟發函數的信息性。h(n)的信息性通俗點說其實就是在估計一個節點的值時的約束條件,如果信息越多或約束條件越多則排除的節點就越多,估價函
數越好或說這個演算法越好。這就是為什麼廣度優先演算法的那麼臭的原因了,誰叫它的h(n)=0,一點啟發信息都沒有。但在游戲開發中由於實時性的問題,h(n)的信息越多,它的計
算量就越大,耗費的時間就越多。就應該適當的減小h(n)的信息,即減小約束條件。但演算法的准確性就差了,這里就有一個平衡的問題。
}

㈣ 星際爭霸2的尋路演算法思路是怎樣的

首先地圖整體開始前,會用多層可達矩陣演算法,算出路徑關鍵點
2,創建關鍵節點可達矩陣
3,再每個兵當前位置對關鍵節點進行路徑計算
這樣可以最小化資源佔用就可以完成路徑計算了,高數的離散數學,挺容易解的

㈤ A*演算法——啟發式路徑搜索

A*是一種路徑搜索演算法,比如為游戲中的角色規劃行動路徑。

A* 演算法的輸入是, 起點(初始狀態) 終點(目標狀態) ,以及兩點間 所有可能的路徑 ,以及涉及到的 中間節點(中間狀態) ,每兩個節點間的路徑的 代價

一般還需要某種 啟發函數 ,即從任意節點到終點的近似代價,啟發函數能夠非常快速的估算出該代價值。

輸出是從 起點到終點的最優路徑 ,即代價最小。同時,好的啟發函數將使得這一搜索運算盡可能高效,即搜索盡量少的節點/可能的路徑。

f(n)=g(n)+h(n)

f(n) 是從初始狀態經由狀態n到目標狀態的代價估計

g(n) 是在狀態空間中從初始狀態到狀態n的實際代價

h(n) 是從狀態n到目標狀態的最佳路徑的估計代價

A*演算法是從起點開始,檢查所有可能的擴展點(它的相鄰點),對每個點計算g+h得到f,在所有可能的擴展點中,選擇f最小的那個點進行擴展,即計算該點的所有可能擴展點的f值,並將這些新的擴展點添加到擴展點列表(open list)。當然,忽略已經在列表中的點、已經考察過的點。

不斷從open list中選擇f值最小的點進行擴展,直到到達目標點(成功找到最優路徑),或者節點用完,路徑搜索失敗。

演算法步驟:

參考

A* 演算法步驟的詳細說明請參考 A*尋路演算法 ,它包含圖文案例清楚的解釋了A*演算法計算步驟的一些細節,本文不再詳細展開。

看一下上面參考文檔中的案例圖,最終搜索完成時,藍色邊框是close list中的節點,綠色邊框是open list中的節點,每個方格中三個數字,左上是f(=g+h),左下是g(已經過路徑的代價),右下是h(估計未經過路徑的代價)。藍色方格始終沿著f值最小的方向搜索前進,避免了對一些不好的路徑(f值較大)的搜索。(圖片來自 A*尋路演算法 )

現在我們可以理解,A*演算法中啟發函數是最重要的,它有幾種情況:

1) h(n) = 0
一種極端情況,如果h(n)是0,則只有g(n)起作用,此時A*演變成Dijkstra演算法,這保證能找到最短路徑。但效率不高,因為得不到啟發。

2) h(n) < 真實代價
如果h(n)經常都比從n移動到目標的實際代價小(或者相等),則A*保證能找到一條最短路徑。h(n)越小,A*擴展的結點越多,運行就得越慢。越接近Dijkstra演算法。

3) h(n) = 真實代價
如果h(n)精確地等於從n移動到目標的代價,則A*將會僅僅尋找最佳路徑而不擴展別的任何結點,這會運行得非常快。盡管這不可能在所有情況下發生,你仍可以在一些特殊情況下讓它們精確地相等(譯者:指讓h(n)精確地等於實際值)。只要提供完美的信息,A*會運行得很完美,認識這一點很好。

4) h(n) > 真實代價
如果h(n)有時比從n移動到目標的實際代價高,則A*不能保證找到一條最短路徑,但它運行得更快。

5) h(n) >> 真實代價
另一種極端情況,如果h(n)比g(n)大很多,則只有h(n)起作用,A*演變成BFS演算法。

關於啟發函數h、Dijkstra演算法、BFS(最佳優先搜索)演算法、路徑規劃情況下啟發函數的選擇、演算法實現時List的數據結構、演算法變種等等更多問題,請參考: A*演算法

閱讀全文

與開放世界尋路演算法相關的資料

熱點內容
雙程2 | 雙程機票:便捷的旅行選擇 瀏覽:578
聯想伺服器如何組建raid0 瀏覽:329
免費看大黃:網路視頻的付費與免費觀看之爭 瀏覽:162
秦大爺第一次上葉思佳的經歷和感受 瀏覽:566
康強:如何提高身體的健康指數 瀏覽:15
程序員上了一年班也沒有提升 瀏覽:202
java繼承重寫 瀏覽:789
各國程序員網址 瀏覽:251
黑暗聖經12集無刪減帶字幕:解讀與影響 瀏覽:933
美麗小蜜桃2:優點、使用技巧和最新版本介紹 瀏覽:477
自助電瓶車app是什麼 瀏覽:986
量子線源碼怎麼看 瀏覽:135
sp打法 | SP打法:提升游戲競技優勢的戰術策略 瀏覽:896
powermill編程好學嗎 瀏覽:892
朱門綉戶紅燒肉明珠 瀏覽:471
事在人為:努力與行動的力量 瀏覽:369
macd背離源碼 瀏覽:812