當前位置:首頁 » 操作系統 » 節點尋路演算法

節點尋路演算法

發布時間: 2022-04-28 06:08:45

㈠ Jps要測量一百五十米的路怎麼找到這條路的中心線

Jps要測量一百五十米的路怎麼找到這條路的中心線:
概念
強迫鄰居(Forced Neighbour)
跳點(Jump Point)
JPS 尋路演算法(Jump Point Search)
實現原理
示例過程
JPS+(Jump Point Search Plus)
預處理
示例過程
總結
參考
概念
JPS(jump point search)演算法實際上是對A* 尋路演算法的一個改進,因此在閱讀本文之前需要先了解A*演算法。A* 演算法在擴展節點時會把節點所有鄰居都考慮進去,這樣openlist中點的數量會很多,搜索效率較慢。
若不了解A*演算法,可以參考博主以前寫的一篇文章 A* 尋路演算法 - KillerAery - 博客園
例如在無遮擋情況下(往往會有多條等價路徑),而我們希望起點到終點實際只取其中一條路徑,而該路徑外其它節點可以沒必要放入openlist(不希望加入沒必要的鄰居)。

其次我們還希望直線方向上中途的點不用放入openlist,如果只放入每段直線子路徑的起點和終點,那openlist又可以少放很多沒必要的節點:

可以看到 JPS 演算法搜到的節點總是「跳躍性」的,這是因為這些關鍵性的節點都是需要改變行走方向的拐點,因此這也是 Jump Point 命名的來歷。
在介紹JPS等演算法具體實現前,我們必須先掌握下面的概念。
強迫鄰居(Forced Neighbour)
強迫鄰居:節點 x 的8個鄰居中有障礙,且 x 的父節點 p 經過x 到達 n 的距離代價比不經過 x 到達的 n 的任意路徑的距離代價小,則稱 n 是 x 的強迫鄰居。
看定義也許十分晦澀難懂。直觀來說,實際就是因為前進方向(父節點到 x 節點的方向為前進方向)的某一邊的靠後位置有障礙物,因此想要到該邊靠前的空位有最短的路徑,就必須得經過過 x 節點。
可能的情況見圖示,黑色為障礙,紅圈即為強迫鄰居:

(左圖為直線方向情況下的強迫鄰居,右圖為斜方向情況下的強迫鄰居)
跳點(Jump Point)
跳點:當前點 x 滿足以下三個條件之一:
節點 x 是起點/終點。
節點 x 至少有一個強迫鄰居。
如果父節點在斜方向(意味著這是斜向搜索),節點x的水平或垂直方向上有滿足條件a,b的點。
節點y的水平或垂直方向是斜向向量的拆解,比如向量d=(1,1),那麼水平方向則是(1,0),並不會往左搜索,只會看右邊,如果向量d=(-1,-1),那麼水平方向是(-1,0),只會搜索左邊,不看右邊,其他同理。
下圖舉個例子,由於黃色節點的父節點是在斜方向,其對應分解成向上和向右兩個方向,因為在右方向發現一個藍色跳點,因此黃色節點也應被判斷為跳點:

JPS 尋路演算法(Jump Point Search)
實現原理
JPS 演算法和A* 演算法非常相似,步驟大概如下:
openlist取一個權值最低的節點,然後開始搜索。(這些和A*是一樣的)
搜索時,先進行 直線搜索(4/8個方向,跳躍搜索),然後再 斜向搜索(4個方向,只搜索一步)。如果期間某個方向搜索到跳點或者碰到障礙(或邊界),則當前方向完成搜索,若有搜到跳點就添加進openlist。
跳躍搜索是指沿直線方向一直搜下去(可能會搜到很多格),直到搜到跳點或者障礙(邊界)。一開始從起點搜索,會有4個直線方向(上下左右),要是4個斜方向都前進了一步,此時直線方向會有8個。
若斜方向沒完成搜索,則斜方向前進一步,重復上述過程。
因為直線方向是跳躍式搜索,所以總是能完成搜索。
若所有方向已完成搜索,則認為當前節點搜索完畢,將當前節點移除於openlist,加入closelist。
重復取openlist權值最低節點搜索,直到openlist為空或者找到終點。
下面結合圖片更好說明過程2和3:首先我們從openlist取出綠色的節點,作為搜索的開始,先進行直線搜索,再斜向搜索,沒有找到任何跳點。

斜方向前進一步後,重復直線搜索和斜向搜索過程,仍沒發現跳點。

斜方向前進兩步後,重復直線搜索和斜向搜索過程,仍沒發現跳點。

斜方向前進了三步後(假設當前位置為 x),在水平直線搜索上發現了一個跳點(紫色節點為強迫鄰居)。

於是 x 也被判斷為跳點,添加進openlist。斜方向結束,綠色節點的搜索過程也就此結束,被移除於openlist,放入closelist。

示例過程
下面展示JPS演算法更加完整的過程:
假設起點為綠色節點,終點為紅色節點。

重復直線搜索和斜向搜索過程,斜方向前進了3步。在第3步判斷出黃色節點為跳點(依據是水平方向有其它跳點),將黃色跳點放入openlist,然後斜方向搜索完成,綠色節點移除於openlist,放入closelist。

對openlist下一個權值最低的節點(即黃色節點)開啟搜索,在直線方向上發現了藍色節點為跳點(依據是紫色節點為強迫鄰居),類似地,放入openlist。

由於斜方向還沒結束,繼續前進一步。最後一次直線搜索和斜向搜索都碰到了邊界,因此黃色節點搜索完成,移除於openlist,放入closelist。

對openlist下一個權值最低的節點(原為藍色節點,下圖變為黃色節點)開啟搜索,直線搜索碰到邊界,斜向搜索無果。斜方繼續前進一步,仍然直線搜索碰到邊界,斜向搜索無果。

由於斜方向還沒結束,繼續前進一步。

最終在直線方向上發現了紅色節點為跳點,因此藍色節點先被判斷為跳點,只添加藍色節點進openlist。斜方向完成,黃色節點搜索完成。

最後openlist取出的藍色節點開啟搜索,在水平方向上發現紅色節點,判斷為終點,演算法完成。
回憶起跳點的第三個判斷條件(如果父節點在斜方向,節點x的水平或垂直方向上有滿足條件a,b的點),會發現這個條件判斷是最復雜的。在尋路過程中,它使尋路多次在水平節點上搜到跳點,也只能先添加它本身。其次,這也是演算法中需要使用到遞歸的地方,是JPS演算法性能瓶頸所在。

㈡ 有關A* 尋路演算法。 看了這個演算法 大致都明白。就是有點不大清楚。

1. B的G值是指從起點A開始,到達該點的最短距離,和B在不在最短路徑上沒有關系。

2. 不是遍歷所有路徑,而是所有點。對於m*n的矩陣, 遍歷所有點的復雜度是m*n(多項式復雜度),而遍歷所有路徑的復雜度是4的(m*n)次冪(每個點都有4個可能的方向)。從冪指數復雜度降低到多項式復雜度,這就是A*演算法的意義所在。

3. 最優路徑是要從終點一步步倒退回來。比如終點的G值是k,那麼最多需要4*k次查找,依然是多項式復雜度。但多數問題(對於純演算法題來說)只是需要知道到達終點的步驟,很少要你找出固定路徑的。

㈢ RMXP尋路演算法

#==============================================================================
# ■ Find_Path
#------------------------------------------------------------------------------
# 尋路演算法--完整滑鼠系統(四方向)專用版
# By whbm
#==============================================================================
class Find_Path
#--------------------------------------------------------------------------
def initialize #初始化
@open_list = []
@close_lise = []
@path = []
end #結束初始化
#--------------------------------------------------------------------------
def fp_passable?(x, y, d, tr_x = -2, tr_y = -2) #開始判定通行
return false if (tr_x == @unable_xa or
tr_x == @unable_xb or
tr_y == @unable_ya or
tr_y == @unable_yb)
if $game_player.passable?(x, y, d)
return true
else
return false
end
end #結束判定通行
#--------------------------------------------------------------------------
def get_g(now_point) #開始計算G值
d = now_point[2]
return 0 if d == 5
father_point = get_father_point(now_point)
g = father_point[3] + 10
return g
end #結束計算G值
#--------------------------------------------------------------------------
def get_h(now_point) #開始計算H值
now_x = now_point[0]
now_y = now_point[1]
#print @trg_x,now_x,@trg_y,now_y
h = (@trg_x - now_x).abs + (@trg_y - now_y).abs
return h * 10
end #結束計算H值
#--------------------------------------------------------------------------
def get_f(now_point) #開始計算F值
f = now_point[3] + now_point[4]
return f
end #結束計算F值
#--------------------------------------------------------------------------
def get_point(x, y) #取已知坐標點
if @open_list.size != 0
@open_list.each do |point|
if point[0] == x and point[1] == y
return point
break
end
end
end
if @close_list.size != 0
@close_list.each do |point|
if point[0] == x and point[1] == y
return point
break
end
end
end
end #結束取已知坐標點
#--------------------------------------------------------------------------
def get_father_point(now_point) #取已知點的父節點
d = now_point[2]
return now_point if d == 5
x = now_point[0] + (d == 6 ? 1 : (d == 4 ? -1 : 0))
y = now_point[1] + (d == 2 ? 1 : (d == 8 ? -1 : 0))
return get_point(x, y)
end #結束取已知點的父節點
#--------------------------------------------------------------------------
def new_point(x, y, d) #開始建立新節點
#print x,y,d
point = [x, y, d]
point.push get_g(point)
point.push get_h(point)
point.push get_f(point)
return point
end #結束建立新節點
#--------------------------------------------------------------------------
def get_direction(self_x, self_y, trg_x, trg_y)
if trg_x > self_x
if trg_y - self_y > - ( trg_x - self_x ) and
trg_y - self_y < ( trg_x - self_x )
return 6
end
if trg_y - self_y > ( trg_x - self_x )
return 2
end
if trg_y - self_y < - ( trg_x - self_x )
return 8
end
end
if trg_x < self_x
if trg_y - self_y > - ( self_x - trg_x ) and
trg_y - self_y < ( self_x - trg_x )
return 4
end
if trg_y - self_y > ( self_x - trg_x )
return 2
end
if trg_y - self_y < - ( self_x - trg_x )
return 8
end
end
end
#--------------------------------------------------------------------------
def get_d_x_y(x, y, d)
d_x = x + (d == 6 ? 1 : (d == 4 ? -1 : 0))
d_y = y + (d == 2 ? 1 : (d == 8 ? -1 : 0))
return d_x, d_y
end
#--------------------------------------------------------------------------
def find_short_path_other(self_x, self_y, trg_x, trg_y,
real_self_x, real_self_y, real_trg_x, real_trg_y)
@self_x = self_x
@self_y = self_y
@now_x = self_x
@now_y = self_y
@trg_x = trg_x
@trg_y = trg_y
@path = []
direction = get_direction(real_self_x, real_self_y, real_trg_x, real_trg_y)
@now_trg_x, @now_trg_y = get_d_x_y(@self_x, @self_y, direction)
while fp_passable?(@now_x, @now_y, direction)
@path.push direction
@now_x = @now_trg_x
@now_y = @now_trg_y
@now_trg_x, @now_trg_y = get_d_x_y(@now_x, @now_y, direction)
end
return @path
end
#--------------------------------------------------------------------------
def find_short_path(self_x, self_y, trg_x, trg_y,
real_self_x, real_self_y, real_trg_x, real_trg_y) #開始搜索路徑

return find_short_path_other(self_x, self_y, trg_x, trg_y,
real_self_x, real_self_y, real_trg_x, real_trg_y) if not
(fp_passable?(trg_x, trg_y + 1, 8) or
fp_passable?(trg_x + 1, trg_y, 4) or
fp_passable?(trg_x - 1, trg_y, 6) or
fp_passable?(trg_x, trg_y - 1, 2)) and @goal_type != 1

#根據屏幕限定搜索麵積..加速
@unable_xa = $game_map.display_x / 128 - 1
@unable_ya = $game_map.display_y / 128 - 1
@unable_xb = $game_map.display_x / 128 + 20
@unable_yb = $game_map.display_y / 128 + 20

@self_x = self_x
@self_y = self_y
@now_x = self_x
@now_y = self_y
@trg_x = trg_x
@trg_y = trg_y
@open_list = []
@close_list = []
#准備搜索
#print @self_x,@self_y
@now_point = new_point(@self_x, @self_y, 5) #令起始點為當前點
@open_list.push @now_point #將當前點加入關閉列表
#開始搜索
begin
loop do
check_trg = check_around_point(@now_point)
if check_trg == true
@path = get_path
break
end
@now_point = get_lowest_f_point
if @now_point == [] or @now_point == nil
@path = []
break
end
end
rescue Hangup
retry
end
return @path
end #結束搜索路徑
#--------------------------------------------------------------------------
def find_player_short_path(trg_x, trg_y,
real_trg_x, real_trg_y) #尋找角色的最短路徑
self_x = $game_player.x
self_y = $game_player.y
real_self_x = $game_player.screen_x
real_self_y = $game_player.screen_y
@goal_type, event = $game_map.check_event_custom_exist(real_trg_x, real_trg_y)
if @goal_type == 1
trg_x = event.x
trg_y = event.y
end
return find_short_path(self_x, self_y, trg_x, trg_y,
real_self_x, real_self_y, real_trg_x, real_trg_y)
end #結束角色的尋找路徑
#--------------------------------------------------------------------------
def get_path #取得最終的路徑
path = []
now_point = @open_list[@open_list.size - 1]
path.push(10 - now_point[2])
last_point = now_point
loop do
now_point = get_father_point(now_point)
break if now_point[2] == 5
path.push(10 - now_point[2])
end
return path.reverse
end #結束取得最終的路徑
#--------------------------------------------------------------------------
def get_lowest_f_point #開始取得最低F值的點
if @open_list == []
return []
end
last_lowest_f_point = @open_list[0]
@open_list.each do |point|
last_lowest_f_point = point if point[5] < last_lowest_f_point[5]
end
return last_lowest_f_point
end #結束取得最低F值點
#--------------------------------------------------------------------------
def check_around_point(point) #開始檢查已知點的八方節點
for d in [2, 4, 6, 8]
x = point[0] + (d == 6 ? 1 : (d == 4 ? -1 : 0))
y = point[1] + (d == 2 ? 1 : (d == 8 ? -1 : 0))
if in_close_list?(x, y) #在關閉列表中
next
elsif in_open_list?(x, y) #在開啟列表中
get_new_g_point = new_point(x, y, 10 - d)
get_last_g_point = get_point(x, y)
if get_new_g_point[3] >= get_last_g_point[3]
next
else
#如果改變父節點是新G值更小則確定改變
@open_list[@open_list.index(get_last_g_point)] = get_new_g_point
end
else
if fp_passable?(point[0], point[1], d, x, y)
# 如果不在開啟列表中、且不在關閉列表中、且通行則添加它到新八周節點
@open_list.push new_point(x, y, 10 - d)
#如果將目標點添加到了開啟列表中就返回true
return true if x == @trg_x and y == @trg_y
return true if @goal_type == 1 and ([1, -1].include?(x - @trg_x) and y - @trg_y == 0) or ([1, -1].include?(y - @trg_y) and x - @trg_x == 0)
end
end
end
#此刻沒有找到目標點並將當前點加入關閉列表並在開啟列表中刪除
@close_list.push point
@open_list.delete(point)
#此刻沒找到目標點並返回false
return false
end #結束計算已知點的八方節點
#--------------------------------------------------------------------------
def in_open_list?(x, y) #開始檢查謀點是否在開啟列表中
@open_list.each do |point|
return true if point[0] == x and point[1] == y
end
return false
end #結束檢查謀點是否在開啟列表中
#--------------------------------------------------------------------------
def in_close_list?(x, y) #開始檢查謀點是否在關閉列表中
@close_list.each do |point|
return true if point[0] == x and point[1] == y
end
return false
end #結束檢查謀點是否在關閉列表中
#--------------------------------------------------------------------------
end

㈣ 從原點出發,遍歷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的大小,從最小路徑的節點向下進行。
}

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

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)的信息,即減小約束條件。但演算法的准確性就差了,這里就有一個平衡的問題。
}

㈥ 游戲中的常用的尋路演算法有哪些

f(n)=g(n)+h(n) 從起始點到目的點的最佳評估值
– 每次都選擇f(n)值最小的結點作為下一個結點,
直到最終達到目的結點
– A*演算法的成功很大程度依賴於h(n)函數的構建
?;) = g(n? 在各種游戲中廣泛應用 Open列表和Closed列表
– Open列表
A*演算法
? h(n) = 從結點n到目的結點的耗費評估值,啟發函數
?,程序返回n
else 生成結點n的每一個後繼結點n;
foreach 結點n的後繼結點n;{
將n』的父結點設置為n
計算啟發式評估函數h(n『)值,評估從n『到node_goal的費用
計算g(n『) = g(n) + 從n』到n的開銷
計算f(n?? 在演算法啟動時,Closed列表為空 A* 演算法偽代碼初始化OPEN列表
初始化CLOSED列表
創建目的結點;稱為node_goal
創建起始結點;稱為node_start
將node_start添加到OPEN列表
while OPEN列表非空{
從OPEN列表中取出f(n)值最低的結點n
將結點n添加到CLOSED列表中
if 結點n與node_goal相等then 我們找到了路徑;)
if n『位於OPEN或者CLOSED列表and 現有f(n)較優then丟棄n』 ;) + h(n?? 包含我們還沒有處理到的結點
? g(n) = 從初始結點到結點n的耗費
?? 包含我們已經處理過的結點
,處理後繼n』
將結點n『從OPEN和CLOSED中刪除
添加結點n『到OPEN列表
}
}
return failure (我們已經搜索了所有的結點?? 啟發式搜索
– 在搜索中涉及到三個函數
??? 我們最開始將起始結點放入到Open列表中
– Closed列表
?

㈦ 最短路徑演算法

Dijkstra演算法,A*演算法和D*演算法

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表為空,或找到目標點。

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

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*演算法和Dijistra演算法的區別在於有無估價值,Dijistra演算法相當於A*演算法中估價值為0的情況。

動態路網,最短路演算法 D*A* 在靜態路網中非常有效(very efficient for static worlds),但不適於在動態路網,環境如權重等不斷變化的動態環境下。

D*是動態A*(D-Star,Dynamic A*) 卡內及梅隆機器人中心的Stentz在1994和1995年兩篇文章提出,主要用於機器人探路。是火星探測器採用的尋路演算法。

主要方法:
1.先用Dijstra演算法從目標節點G向起始節點搜索。儲存路網中目標點到各個節點的最短路和該位置到目標點的實際值h,k(k為所有變化h之中最小的值,當前為k=h。每個節點包含上一節點到目標點的最短路信息1(2),2(5),5(4),4(7)。則1到4的最短路為1-2-5-4。
原OPEN和CLOSE中節點信息保存。
2.機器人沿最短路開始移動,在移動的下一節點沒有變化時,無需計算,利用上一步Dijstra計算出的最短路信息從出發點向後追述即可,當在Y點探測到下一節點X狀態發生改變,如堵塞。機器人首先調整自己在當前位置Y到目標點G的實際值h(Y),h(Y)=X到Y的新權值c(X,Y)+X的原實際值h(X).X為下一節點(到目標點方向Y->X->G),Y是當前點。k值取h值變化前後的最小。
3.用A*或其它演算法計算,這里假設用A*演算法,遍歷Y的子節點,點放入CLOSE,調整Y的子節點a的h值,h(a)=h(Y)+Y到子節點a的權重C(Y,a),比較a點是否存在於OPEN和CLOSE中,方法如下:
while()
{
從OPEN表中取k值最小的節點Y;
遍歷Y的子節點a,計算a的h值 h(a)=h(Y)+Y到子節點a的權重C(Y,a)
{
if(a in OPEN) 比較兩個a的h值
if( a的h值小於OPEN表a的h值 )
{ 更新OPEN表中a的h值;k值取最小的h值
有未受影響的最短路經存在
break;
}
if(a in CLOSE) 比較兩個a的h值 //注意是同一個節點的兩個不同路徑的估價值
if( a的h值小於CLOSE表的h值 )
{
更新CLOSE表中a的h值; k值取最小的h值;將a節點放入OPEN表
有未受影響的最短路經存在
break;
}
if(a not in both)
將a插入OPEN表中; //還沒有排序
}
放Y到CLOSE表;
OPEN表比較k值大小進行排序;
}
機器人利用第一步Dijstra計算出的最短路信息從a點到目標點的最短路經進行。

D*演算法在動態環境中尋路非常有效,向目標點移動中,只檢查最短路徑上下一節點或臨近節點的變化情況,如機器人尋路等情況。對於距離遠的最短路徑上發生的變化,則感覺不太適用。

㈧ a*尋路演算法如果f值和h值都相等怎麼取最優節點

首先,G值是從開始點到當前點的移動量,H值是從當前點到終點的移動估算量。既然F=G+H.如果F值和H值都相同,那麼G值也是相同的,也就是說從開始點走了同樣的距離,移動到兩個不同的節點,而這兩個節點距離重點的距離也是相同的。那就繼續往下進行演算法。如果繼續下去之後,這兩個節點還是一樣的情況,那說明有兩條最優路徑,不然一定會有一個節點會被淘汰。

㈨ C++尋路演算法

迷宮尋找路徑要不。。。。。。#include <iostream>
#include<iomanip>
using namespace std;
#define M 10
#define N 10
typedef enum{X=0,up,dn,rt,lt} tDir; //搜索方向
class Migong
{
public:
int tag; /*0 1*/
tDir comeDir; /*退回*/
int up,rt,dn,lt; //方向
int back;
};int m[M][N]={ //初始化通道數據
{0,0,1,1,1,1,1,1,1,1},
{1,0,1,1,1,0,1,1,1,1},
{1,0,0,0,1,0,1,1,1,1},
{1,1,1,0,1,1,1,1,1,1},
{1,0,0,0,1,0,0,0,1,1},
{1,0,1,1,1,0,1,0,1,1},
{1,0,1,0,0,0,1,0,0,1},
{1,0,0,0,1,1,0,1,0,1},
{1,1,1,1,1,1,0,1,0,1},
{1,1,1,1,1,1,1,1,0,0},
}; int ini=0,inj=0; //入點
int outi=9,outj=9; //出口
int cnt=0; //從入口到出口需多少步
int path[M][N]; //記錄找到路徑後的迷宮
Migong maze[10][10]; void initmaze(Migong mz[][10]) //初始化迷宮數據
{
int i;
int j;
for(i=0;i<10;i++)
for(j=0;j<10;j++)
{
mz[i][j].tag=m[i][j];
mz[i][j].comeDir=X;
mz[i][j].up=0;
mz[i][j].dn=0;
mz[i][j].rt=0;
mz[i][j].lt=0;
mz[i][j].back=0;
}
}int find(Migong mz[][10],int i,int j,tDir dir) //搜索路徑
{
if(i==outi&&j==outj)
return 1; ////if 當前節點是出口 then return 1;
if(dir!=X) //if 不是是回退到本節點,then 記錄來的方向 根據來的方向設定其相對方向已走
{
mz[i][j].comeDir=dir;
if(dir==up)
mz[i][j].dn=1; //向N方向沒有走&&可以走,則向N遞歸走
if(dir==dn)
mz[i][j].up=1; //向E方向沒有走&&可以走,則向N遞歸走
if(dir==rt)
mz[i][j].lt=1; //向S方向沒有走&&可以走,則向N遞歸走
if(dir==lt)
mz[i][j].rt=1; //向W方向沒有走&&可以走,則向N遞歸走
}
if(mz[i][j].up==0) //if 向up方向沒走&&不越界&&可以走 則向up遞歸走
{
int ni;
int nj;
mz[i][j].up=1; //記錄本節點
ni=i-1;
nj=j; //ni,nj表示i,j的上一個坐標
if(ni>=0 && mz[ni][nj].tag==0)
if(find(maze,ni,nj,up))
return 1;
}
if(mz[i][j].dn==0) //if 向dn方向沒走&&不越界&&可以走 則向dn遞歸走
{
int ni;
int nj;
mz[i][j].dn=1; //記錄本節點
ni=i+1;
nj=j; //ni,nj表示i,j的下一個坐標
if(ni<10 && mz[ni][nj].tag==0)
if(find(maze,ni,nj,dn))
return 1;
}
if(mz[i][j].rt==0) //if 向rt方向沒走&&不越界&&可以走 則向rt遞歸走
{
int ni;
int nj;
mz[i][j].rt=1; //記錄本節點
ni=i;
nj=j+1; //ni,nj表示i,j的右一個坐標
if(nj<10 && mz[ni][nj].tag==0)
if(find(maze,ni,nj,rt))
return 1;
}
if(mz[i][j].lt==0) //if 向lt方向沒走&&不越界&&可以走 則向lt遞歸走
{
int ni;
int nj;
mz[i][j].lt=1; //記錄本節點
ni=i;
nj=j-1; //ni,nj表示i,j的左一個坐標
if(nj>=0 && mz[ni][nj].tag==0)
if(find(maze,ni,nj,lt))
return 1;
}

//四個方向都走完了還沒有結果

if(i==ini && j==inj) // if 是入口 return 0
return 0;
else // else 則回退
{
mz[i][j].back=1;
if(mz[i][j].comeDir=up) //如果回退的值等於up的值,則向up方向搜索
{
int ni;
int nj;
ni=i+1;
nj=j; //ni,nj表示i,j的下一個坐標
if(find(maze,ni,nj,X))
return 1;
}
if(mz[i][j].comeDir=dn) //如果回退的值等於dn的值,則向dn方向搜索
{
int ni;
int nj;
ni=i-1;
nj=j; //ni,nj表示i,j的上一個坐標
if(find(maze,ni,nj,X))
return 1;
}
if(mz[i][j].comeDir=rt) //如果回退的值等於rt的值,則向rt方向搜索
{
int ni;
int nj;
ni=i;
nj=j-1; //ni,nj表示i,j的左一個坐標
if(find(maze,ni,nj,X))
return 1;
}
if(mz[i][j].comeDir=lt) //如果回退的值等於lt的值,則向lt方向搜索
{
int ni;
int nj;
ni=i+1;
nj=j+1; //ni,nj表示i,j的左下角一個坐標
if(find(maze,ni,nj,X))
return 1;
}
}
return 0;
}int onway( Migong nd) //判斷點是否在路徑上
{
if(nd.tag!=0)
return 0; //牆
if(nd.up==0&&nd.dn==0&&nd.rt==0&&nd.lt==0)
return 0; //沒訪問過
if(nd.up==1&&nd.dn==1&&nd.rt==1&&nd.lt==1&&nd.back==1)
return 0; //訪問過但不通
return 1;
}//列印
void print( Migong mz[][10]) //列印原迷宮
{
int i;
int j;
cout<<"0表示可通過,1表示牆"<<endl;
cout<<"-------------------------------";
cout<<endl<<" ";
cout<<"▂▂▂▂▂▂▂▂"<<endl;
for(i=0;i<10;i++)
{
cout<<setw(10)<<"▎ ";
for(j=0;j<10;j++)

cout<<mz[i][j].tag;
cout<<" ▎"<<endl;

}
cout<<" ";
cout<<"▂▂▂▂▂▂▂▂"<<endl;
}void print1( Migong mz[][10]) //列印含路徑迷宮
{
int i;
int j;
cout<<endl<<" ";
cout<<"▂▂▂▂▂▂▂▂"<<endl;

for(i=0;i<10;i++)
{
cout<<setw(10)<<"▎ ";
for(j=0;j<10;j++)
{
if(i==9 && j==9) //出口
{
cnt++;
cout<<"*";
path[i][j]=0;
}
else
if(onway(mz[i][j]))
{
cout<<"*"; //*表示路徑
cnt++;
path[i][j];
}
else
{
cout<<mz[i][j].tag;
path[i][j]=1; //path[i][j]=0表示可通過,path[i][j]=1表示牆
} }
cout<<" ▎"<<endl;
}cout<<" ";
cout<<"▂▂▂▂▂▂▂▂"<<endl;
}void print2( Migong mz[][10]) //列印路徑坐標
{
int i;
int j;
int di;
int dj; //di,dj的值為-1,0,1,為了搜索坐標i,j附近的坐標
int pi;
int pj; //pi,pj為上一個路徑坐標
int r;
int count; //統計輸出了多少個坐標
i=0;
j=0;
pi=1;
pj=0;
count=0; cout<<endl<<"路徑坐標為:"<<endl<<endl;
for(r=0;r<cnt;r++)
{
if(i>=10 || j>=10) //i,j的值不可能大於10
continue;
else
{
for(di=-1;di<2;di++)
for(dj=-1;dj<2;dj++)
{
if(di==dj ) //path[i][j]的下一步不可能在它的左上角和右下角
continue;
if(di==1 && dj==-1) //path[i][j]的下一步不可能在它的左下角
continue;
if(di==-1 && dj==1) //path[i][j]的下一步不可能在它的右上角
continue;
if((i+di)<0 ||(j+dj)<0) //i+di,j+dj小於0時不符
continue;
if(path[i+di][j+dj]!=0) //i+di,j+dj不是路徑上的坐標
continue;
if((i+di)==i && (j+dj)==j ) //path[i][j]的下一步不可能是它本身
continue;
else
if((i+di)==pi && (j+dj)==pj) //path[i][j]的下一步不可能是它的上一步
continue;
else
{if(i==9&&j==9)<br> cout<<"(9,9)";<br> else<br> {<br> <br> cout<<"("<<i<<","<<j<<")"<<"->";<br> count++;<br> if(count%5==0)<br> cout<<endl;<br> }
pi=i;
pj=j;
i=i+di;
j=j+dj; }
}
}
}
}int main()
{
initmaze(maze); //初始化迷宮
cout<<endl<<endl<<"原迷宮如下:"<<endl;
print(maze); //列印原迷宮
if (find(maze,ini,inj,rt)) //如果迷宮有路徑
{

cout<<"-------------------------------";
cout<<endl<<"含路徑的迷宮,*表示通道"<<endl;
cout<<"-------------------------------";
print1(maze); // 輸出含路徑的迷宮
cout<<endl<<"-------------------------------"<<endl;
print2(maze); //輸出路徑坐標
}
else
cout<<"no way!"; //如果迷宮沒路徑,輸出no way
cout<<endl<<endl<<endl;
cout<<"從入口到出口需"<<cnt<<"步";
cout<<endl<<endl;
return 0;
}

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

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

熱點內容
python計算pdf 發布:2024-10-04 13:31:19 瀏覽:547
win7無法訪問nas 發布:2024-10-04 13:31:16 瀏覽:544
hibernate存儲blob 發布:2024-10-04 13:16:22 瀏覽:962
ppsspp安卓文件夾 發布:2024-10-04 13:02:11 瀏覽:587
android多listview 發布:2024-10-04 13:02:07 瀏覽:11
isp會限制ftp嗎 發布:2024-10-04 13:02:04 瀏覽:98
20兆電信光纖上傳速度 發布:2024-10-04 12:44:34 瀏覽:719
重命名文件夾linux 發布:2024-10-04 12:44:25 瀏覽:616
怎樣在qq發送文件夾 發布:2024-10-04 12:44:25 瀏覽:360
加密狗發票 發布:2024-10-04 12:37:53 瀏覽:432