【Unity學習筆記】A*尋路算法

在這里插入圖片描述


文章目錄

    • 尋路算法
      • BFS廣度優先算法
      • DFS深度優先
      • 貪心算法
    • 引入權重
      • Dijkstra算法
  • A*算法
  • C#實現
    • 步驟
  • Unity中的A*算法
    • A*優化建議


圖的知識盤點

pathfinding

作為一名計算機專業的學生,對于圖這種數據結構也是爛熟于心了。圖是一種包含了多個結點的數據結構,它是結點和路徑的集合。可以用鄰接表和鄰接矩陣來表示一張圖。

圖的表示可以通過計算得到結點之間的可達和不可達,耗費的代價等等。在許多數學問題上十分有用。通常解決圖問題的算法被我們稱為尋路算法。

尋路算法

在大學期間,我們就學習過一些基本的尋路算法:

BFS廣度優先算法

在這里插入圖片描述
廣度優先算法的原理是,以起始點為中心,向四周的相鄰點(也就是與當前點連通且路長為1的那些節點)依次遍歷。當遍歷完相鄰節點后,再遍歷相鄰結點的相鄰點,依次類推。

在這里插入圖片描述

當找到結束點后,只需要從終點開始,反向按著相鄰節點的最小遍歷序號數尋找,就能找到最短路徑了

DFS深度優先

在這里插入圖片描述

如果說廣度優先是以中心向四周擴散的圓形方式尋找,深度優先就是一條線的一直找下去。深度優先不斷的尋找未經過的相鄰節點,直到不再有可遍歷的相鄰節點才會考慮回退到上一個節點并再換一個方向找。

深度優先算法其實更適合在樹種的查找,而在圖中特別是當一些圖的節點是全連通的時候,深度優先就很難用了。

貪心算法

貪心算法適用于路徑帶有不同權值的時候,遍歷時我們優先遍歷相鄰結點中權值較小者,這樣做的好處是如果找到了路徑,那么我們的路徑一定是部分最短的(相鄰結點永遠是最短的,雖然不一定是全局最短,但是相對來說不會是最差的)


引入權重

現在我們要為尋路算法引入權重值,每個結點的權重值不一樣,權重值由起點和終點的距離決定,權重越小則距離越小。

Dijkstra算法

在這里插入圖片描述
Dijkstra算法的原理是先算出起始點到其他點的最短路徑,再求解。

例如以上圖點1到點3為例,第一輪中找到點1到相鄰點的最短路徑是v1-v5,cost為5。那么我們就按著這個最短路徑走,接著第二輪從點v5開始計算v5到其他點的路徑長度。依次類推,按照表格上的路徑,在第二輪發現v4達到不了v3,因此我們放棄這條路徑,再次回到第二輪,選擇除了這條路徑以外最短的,也就是v1-v5-v2,按照這條路徑走發現是可以到達v3的,此時就是我們的最短路徑。

當找不到最短路徑時,就要回退到本輪的第二短,本輪第二短達不到就第三短…以此類推。若本輪所有路徑都不可達,那就回退到上一輪,選擇上一輪中未選擇的路徑。

當圖為網格圖,且每個結點之間的移動代價相等時,Dijkstra就等于廣度優先


現在讓我們引入權值計算公式:默認權值為起點和終點間的距離
a b s ( s t a r t . x ? e n d . x ) + a b s ( s t a r t . y ? e n d . y ) abs(start.x - end.x) + abs(start.y - end.y) abs(start.x?end.x)+abs(start.y?end.y)

對比Dijkstra算法和貪心算法,在簡單的情況下貪心算法更有優勢:

在這里插入圖片描述
而一旦出現了復雜的地形,貪心算法就不一定是有效的了:

在這里插入圖片描述


A*算法

之前講了這么多,介紹了一些常見的尋路算法。Dijkstra效果好但是可能造成時間上的浪費,貪心算法速度快,但是最終的結果不一定是最短路徑。

因此我們要學習A*算法:

在這里插入圖片描述

在A*算法下,找到的路徑長度將是最短的,且用時要比Dijkstra算法要小。

A*算法是一種啟發式算法,它通過這個函數來計算每個結點的優先級:

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

其中

  • f(n)是節點n的綜合優先級。當我們選擇下一個要遍歷的節點時,我們總會選取綜合優先級最高(值最小)的節點。
  • g(n) 是節點n距離起點的代價。
  • h(n)是節點n距離終點的預計代價,這也就是A*算法的啟發函數。關于啟發函數我們在下面詳細講解。

A*算法在運算過程中,每次從優先隊列中選取f(n)值最小(優先級最高)的結點作為下一個待遍歷的節點。而不是類似Dijkstra算法,每次遍歷相鄰結點時盡管下一個結點可能出現權值過大的情況,但是我們不能確保它不是全局最優的,因此我們依然要把它加入到遍歷路徑中。

而相比下貪心算法雖然局部最優,但也不能確保是全局最優解。

A*算法的高明之處在于,除了實際代價,還有預估代價作為參考,當遍歷結點越接近終點,則 g ( n ) 越大, h ( n ) 越小 g(n)越大,h(n)越小 g(n)越大,h(n)越小,因此往往在最短路徑上的結點值 f ( n ) f(n) f(n)相差不大。因此我們可以用貪心算法選取優先路徑,再用Dijkstra進行遍歷。遍歷的節點數量也小于Dijkstra算法 。

如果選取的啟發函數有問題,那么結果可能更偏向Dijkstra算法。


C#實現

版權聲明:本文為博主原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接和本聲明。
原文鏈接:https://blog.csdn.net/qq_60125117/article/details/130233023

轉自C# A*算法,總結的太好了,我就直接抄了

A*算法使用一個開放列表(open list)和一個封閉列表(closed list)來維護搜索過程。開放列表存儲待擴展的節點,而封閉列表存儲已經擴展過的節點,以避免重復擴展節點。

在搜索過程中,我們從開放列表中選擇f值最小的節點進行擴展,并將其加入封閉列表中。如果該節點是目標狀態,則搜索結束,并返回從起點到目標狀態的最短路徑。

步驟

  1. 將起點加入開放列表,并將其代價設置為0。
  2. 從開放列表中選擇代價 f ( n ) f(n) f(n)值最小的節點進行擴展,即優先選擇離目標狀態更接近的節點。
  3. 將該節點從開放列表中移除,并加入封閉列表中。
  4. 對該節點的所有相鄰節點進行以下操作:
    1. 如果該節點已經在封閉列表中,則忽略該節點
    2. 如果該節點不在開放列表中,則將其加入開放列表,并將其代價和父節點設置為當前節點
    3. 如果該節點已經在開放列表中,則比較當前節點到該節點的代價和已有的代價,選擇代價較小的路徑,并更新該節點的代價和父節點。
  5. 重復步驟2-4,直到開放列表為空或找到目標狀態。
  6. 如果找到目標狀態,則從目標狀態開始回溯路徑,直到回溯到初始狀態。
public List<Node> FindPath(Node start, Node end)
{// 存儲已訪問的節點var closedSet = new HashSet<Node>();// 存儲待訪問的節點var openSet = new Heap<Node>(nodeComparer);openSet.Add(start);// 存儲節點到起點的實際代價var gScore = new Dictionary<Node, float>();gScore[start] = 0;// 存儲節點到終點的估計代價var hScore = new Dictionary<Node, float>();hScore[start] = HeuristicCostEstimate(start, end);// 存儲每個節點的父節點,用于回溯路徑var cameFrom = new Dictionary<Node, Node>();while (openSet.Count > 0){// 獲取最小估價的節點var current = openSet.RemoveFirst();if (current == end){// 找到目標狀態,回溯路徑var path = new List<Node>();while (current != start){path.Add(current);current = cameFrom[current];}path.Reverse();return path;}// 標記當前節點已訪問closedSet.Add(current);// 遍歷當前節點的相鄰節點foreach (var neighbor in current.Neighbors){if (closedSet.Contains(neighbor))continue; // 相鄰節點已經訪問過了// 計算當前節點到相鄰節點的實際代價// 關于代價函數t(n)=g(n)+h(n),其中啟發函數h(n)是可以自定義的,只要效果好就行var tentativeGScore = gScore[current] + DistanceBetween(current, neighbor);// 如果相鄰節點不在待訪問列表中,或者到相鄰節點的代價更小if (!openSet.Contains(neighbor) || tentativeGScore < gScore[neighbor]){// 更新相鄰節點的父節點和代價cameFrom[neighbor] = current;gScore[neighbor] = tentativeGScore;hScore[neighbor] = HeuristicCostEstimate(neighbor, end);// 如果相鄰節點不在待訪問列表中,加入待訪問列表if (!openSet.Contains(neighbor))openSet.Add(neighbor);}}}// 找不到目標狀態,返回空列表return new List<Node>();
}

找到最終結點后,我們只需要從終點開始,一路沿著相鄰的OpenList結點中的最小值回溯即可找到尋路的路徑。


Unity中的A*算法

Unity中的A算法是一種常用的尋路算法,用于計算在網格或圖形地圖上找到最短路徑。A算法基于圖搜索和啟發式評估,具有較高的效率和準確性。

其實Unity中要使用A*算法,就是對地圖模型的抽象,將其抽象為結點構成的圖。我們可以分割網格,或者自定義結點坐標來實現。總之原理是一樣的,就是需要抽象出結點的概念:

  1. 創建網格或圖形地圖:將游戲場景分割為一系列網格或節點,并構建地圖數據結構,用于存儲每個節點的信息,如位置、連接關系和代價。
  2. 定義節點的啟發式評估函數:A*算法使用啟發式函數來估計從當前節點到目標節點的代價。這個函數通常基于節點之間的距離或其他因素,用于指導搜索過程。
  3. 實現Open列表和Closed列表:Open列表存儲待評估的節點,Closed列表存儲已評估過的節點。開始時,將起始節點添加到Open列表中。
  4. 迭代搜索過程:循環執行以下步驟直到找到目標節點或Open列表為空:
    1. 從Open列表中選擇代價最小的節點,作為當前節點。
    2. 將當前節點從Open列表中移除,并添加到Closed列表中。
    3. 檢查當前節點是否為目標節點,如果是,則路徑搜索完成。
    4. 否則,對當前節點的相鄰節點進行遍歷

A*算法的性能和效果受到地圖復雜度、啟發式函數的選擇以及路徑平滑等因素的影響。在實際使用中,可以根據具體需求對算法進行調優和優化


A*優化建議

如果需要對A*算法進行性能優化,可以考慮以下幾點:

  1. 使用優先隊列:A*算法需要頻繁地從開放列表中取出具有最小代價的節點,因此使用優先隊列可以提高算法的效率。
  2. 使用啟發式算法:啟發式算法可以在搜索過程中盡可能地快速地找到目標節點,從而提高算法效率。在實現過程中,需要設計一個好的估價函數,以便盡可能減少搜索的節點數。(好像煉丹啊)
  3. 剪枝:A*算法中有一些無用的搜索節點,可以使用剪枝技術將其剪掉,從而減少搜索時間。
  4. 預處理:預處理是指對搜索的地圖進行預處理,以便在搜索過程中可以快速地獲取地圖信息,從而提高搜索效率。

還有一種針對靜態地圖的優化方法:使用預處理的路線圖(Precomputed Roadmap)。

預處理的路線圖是一種離線生成的數據結構,它將地圖劃分為一些相互連接的區域,并計算出每個區域之間的最短路徑。在搜索過程中,可以直接使用預處理的路線圖,從而避免了大量的搜索操作。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/39574.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/39574.shtml
英文地址,請注明出處:http://en.pswp.cn/web/39574.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

案例分享:數據集市搭建方案中集成SQLFlow數據血緣分析工具

本文中描述的數據集市搭建方案是一家跨國公司在AWS平臺上的具體實踐案例。我公司參與其中的數據血緣部分的建設&#xff0c;SQLFlow數據血緣分析工具在該方案中幫助用戶實現了數據血緣分析。 用戶使用Redshift 數據庫倉庫進行數據集市開發。從各種數據源提取數據&#xff0c;并…

動態代理(通俗易懂)

程序為什么需要代理&#xff1f;代理長什么樣&#xff1f; 例子 梳理 代理對象(接口)&#xff1a;要包含被代理的對象的方法 ---Star 被代理對象&#xff1a;要實現代理對象(接口) ---SuperStar 代理工具類&#xff1a;創建一個代理&#xff0c;返回值用代理對象&#xff0c…

羅克韋爾 AB 1756-OA16控制器 模塊 處理器

羅克韋爾 AB 1756-OA16該模塊是任何自動化系統的重要組成部分&#xff0c;提供對各種過程的精確控制。它被設計為易于安裝和使用&#xff0c;具有用戶友好的界面&#xff0c;允許簡單的配置和監控。 羅克韋爾 AB 1756-OA16控制器是一款為工業應用而設計的先進控制系統。它具有…

React快速入門-跟著AI學習react

React的快速入門可以遵循以下步驟進行&#xff0c;我將結合參考文章中的相關信息&#xff0c;以分點表示和歸納的形式給出詳細步驟&#xff1a; 一、React基礎知識了解 React的概念和特點&#xff1a; React是一個專注于構建用戶界面的JavaScript庫&#xff0c;采用聲明式設計…

python將多個文件夾里面的文件拷貝到一個文件夾中

網上可以搜到很多方式&#xff0c;有的好使&#xff0c;有的不好使&#xff0c;親測如下腳本可用&#xff0c;并可達到我想要的效果&#xff0c;只將多個文件夾里的文件拷貝到一個文件夾中&#xff0c;不拷貝文件夾本身&#xff0c;如果需要文件夾也拷貝打開注釋行即可 import…

初次使用GitHub教程入門

注冊一個github賬戶 訪問地址&#xff1a;https://github.com/&#xff0c;點擊右上角sign up&#xff0c;錄入以下信息&#xff0c;郵箱&#xff0c;密碼&#xff0c;賬號&#xff0c;會有郵箱驗證&#xff0c;跟著步驟來就好了 配置 本機上設置你的github的郵箱和用戶名 …

51-5 權限維持2 - 影子賬號(隱藏用戶)

權限維持技術 權限維持技術(Persistence,也稱為權限持久化)是一種能夠在系統重啟、用戶更改密碼或其他可能導致訪問中斷的情況下保持對系統訪問的技術。例如,它包括創建系統服務、利用計劃任務、修改系統啟動項或注冊表、以及映像劫持等方法。 創建影子賬戶 影子賬戶是指隱…

【管理咨詢寶藏139】某大型快消集團公司多渠道銷售管理體系方案

本報告首發于公號“管理咨詢寶藏”&#xff0c;如需閱讀完整版報告內容&#xff0c;請查閱公號“管理咨詢寶藏”。 【管理咨詢寶藏139】某大型快消集團公司多渠道銷售管理體系方案 【格式】PDF版本 【關鍵詞】羅蘭貝格、營銷咨詢、戰略規劃 【核心觀點】 - 銷售體系建設主要需…

谷粒商城學習-06-使用vagrant快速創建linux虛擬機

這一節的內容是在Windows上安裝虛擬機。 為什么要按照虛擬機呢&#xff1f; 原因是很多軟件只能在Linux下運行&#xff0c;有的雖然也可以在Windows上運行&#xff0c;但從安裝到運行會遇到很多問題&#xff0c;為這些解決這些問題花時間對于大多數人特別是初學者是沒有什么價…

數字人直播源碼開發全攻略揭秘:如何搭建自己的數字人直播平臺?

當前&#xff0c;數字人直播逐漸成為眾多中小型企業線上帶貨和品牌宣傳的不二之選&#xff0c;而艾媒研究數據也顯示&#xff0c;超五成以上的被調查群體的企業使用過虛擬人技術&#xff0c;超三成被調查群體的企業計劃使用虛擬人技術。在此背景下&#xff0c;越來越多的創業者…

android應用的持續構建CI(一)-- 總體設計

一、背景 接下里我希望通過一系列的文章&#xff0c;把android應用的構建梳理一遍&#xff0c;從總體設計到逐個環節的實現。 總體設計jenkins集成手動簽名依賴環境應用管理 二、構建流程圖 三、技術組件 jenkinsjdkgradle360加固 既然是android應用的持續構建&#xff0c…

記錄一次解決循環依賴

場景 寫權限模塊-登錄驗證這一塊的時候&#xff0c;遇到了一個比較有意思的問題&#xff0c;循環依賴: The dependencies of some of the beans in the application context form a cycle:userController defined in file xxx↓userServiceImpl defined in file xxxx ┌───…

Web3 開發者入門手冊:技能、工具和職業前景

原文&#xff1a;https://remote3.co/blog-post/how-to-become-a-web3-developer 作者&#xff1a;Paul Anderson 編譯&#xff1a;TinTinLand Web3 是 2024 年科技領域最受矚目的話題之一——Web3 令人激動的實用潛力可以跨越多個行業&#xff0c;早期采用者更有機會在未來…

TortoiseSVN 使用教程

TortoiseSVN 使用教程 1. 引言 TortoiseSVN 是一個開源的版本控制系統,它基于 Subversion(SVN)系統,為 Windows 操作系統提供了一套方便的圖形用戶界面。通過 TortoiseSVN,用戶可以輕松地管理文件的版本,進行團隊協作,以及跟蹤文件的變更歷史。本教程將詳細介紹 Torto…

亞馬遜云服務器的價格真的那么貴嗎?一年要花多少錢?

亞馬遜Web服務&#xff08;AWS&#xff09;作為全球領先的云計算平臺&#xff0c;其定價策略常常引起用戶的關注。很多人可能會問&#xff1a;"AWS真的那么貴嗎&#xff1f;"實際上&#xff0c;這個問題的答案并不是簡單的"是"或"否"&#xff0c…

【大數據綜合試驗區1008】揭秘企業數字化轉型:大數據試驗區政策數據集大公開!

今天給大家分享的是國內頂級期刊中國工業經濟2023年發布的最新期刊《政策賦能、數字生態與企業數字化轉型——基于國家大數據綜合試驗區的準自然實驗》文章中所使用到的數據集——國家大數據綜合試驗區政策數據集以及工具變量數據&#xff0c;該文章基于2009-2019年中國上市企業…

【代碼隨想錄_Day24】134. 加油站 135. 分發糖果 860. 檸檬水找零 406. 根據身高重建隊列

Day24 OK&#xff0c;今日份的打卡&#xff01;第二十四天 以下是今日份的總結加油站分發糖果檸檬水找零根據身高重建隊列 以下是今日份的總結 加油站分發糖果檸檬水找零根據身高重建隊列 今天的題目難度不低&#xff0c;而且非常的有意思&#xff0c;盡量還是寫一些簡潔代碼…

花鍵參數確定的流程是怎么樣的?

繼續花鍵的話題&#xff0c;今天跟小伙伴們一同學習一下&#xff1a;漸開線花鍵的參數確定的一般流程及基本方法。 前面有好幾篇介紹了花鍵的基本參數的概念&#xff0c;包括規格、模數、齒數、壓力角等等。以及花鍵的定心方式&#xff0c;內外花鍵的配合方式。那么這些參數的…

ARM架構 AArch64 基礎知識介紹

介紹 aarch64是 ARM 架構的 64 位版本&#xff0c;它是 ARMv8 架構的一部分&#xff0c;被設計用來提供更高的性能和更大的地址空間&#xff0c;同時保持與 32 位 ARM 架構的兼容性。AArch64 是 ARMv8 的 64 位指令集架構&#xff08;ISA&#xff09;&#xff0c;它提供了豐富的…

2023 最新版IntelliJ IDEA 2023.1創建Java Web前(vue3)后端(spring-boot3)分離 項目詳細步驟(圖文詳解)

文章目錄 &#x1f6a9; 接上篇&#x1f3f3;?&#x1f308; 項目構建所需的相關工具JavaIDEAmavenNodeJSVueVisual Studio Code &#x1f30c; 后端項目創建詳細步驟&#x1f6eb; 1、開始創建新項目&#x1f6eb; 2、輸入項目名稱、選擇項目存儲位置、項目管理工具&#xff…