三、prim演算法和迷宮生成
1.我們將迷宮定義如下:迷宮由道路
和牆
組成,且迷宮中道路
上的任意兩點應互相可達
2.隨機迷宮生成演算法一般有以下三種,這裡只介紹隨機prim演算法
最小生成樹
:在帶權圖g=( v,e )中(v為點集,e為邊集且每條邊帶有權值),我們希望找到e的乙個無環子集t,使得v中任意兩點可達。由於t無環且聯通所有點,可知t必為一顆樹,稱這種邊子集t為生成樹
,稱所有滿足條件的t中權值和最小的為最小生成樹
。
舉例來說,我們繪製一塊pcb電路板,需要把n個針腳佈線連線在一起,並希望連線長度總和最小。這裡n個針腳即為點集,任意兩針腳間的所有可能連線組成這個pcb圖的邊集,而連線的長度可看做該線的權值。任意乙個連線所有針腳且不產生連線回環的連法都是此pcb圖的乙個生成樹,所有生成樹中用線長度最短的即為最小生成樹.
prim是求給定若干點間最小生成樹的經典演算法。另一種此問題的經典演算法是kruskal演算法
prim演算法使用的是貪心策略,其正確性可以證明。
演算法流程如下:
使用迴圈不變式來證明演算法正確性,關於迴圈不變式可以參考:迴圈不變式的思想及其應用
prim演算法要管理的集合a遵循以下迴圈不變式:在每遍迴圈前,a是某最小生成樹的乙個子集。也就是說,我們要在每一步迴圈找到乙個邊(u,v),使得 a∪也是某最小生成樹的子集,我們可以定義滿足這個要求的邊為安全邊
按以下方式使用迴圈不變式證明正確性
1 a=∅
2while a不是最小生成樹
3 找到安全邊(u,v)
4 a=a∪
5return a
初始化:在第一行後,a直接滿足迴圈不變式
保持:演算法第2~4行一直加入安全邊,不會破壞迴圈不變式
終止:所有加入a的邊都屬於某最小生成樹,則第5行返回的a一定是乙個最小生成樹
上述策略的重點在於第3行,如何找到一條安全邊。(這條安全邊是必然存在的,因為迴圈不變式告訴我們一定存在乙個最小生成樹t滿足a∈t,2~4行時a是t的真子集,一定有邊(u,v)∈ t && (u,v)∉ a,此邊即為安全邊)
為了辨別安全邊,先證明以下定理:
設t是包含a的乙個最小生成樹,有切割(s,v-s)尊重a,它的輕量級邊為(u,v)
∵t為乙個最小生成樹,連通圖中任意兩點
∴點u,v間存在簡單路徑p∈t
∵點u,v分處於切割兩側
∴必存在邊(x,y)∈ p且橫跨切割(s,v-s)
∵t中無環,p唯一
∴刪除邊(x,y)會使t被分解為兩個連通分量
∴將(u,v)加入這兩個連通分量可以生成新的生成樹t'
∵權值w(
(u,v)
)<=w(
(x,y)
)∴w(t')
<=w(t)
∴t'也是最小生成樹
∵切割(s,v-s)尊重a
∴(x,y)∉ a
又∵a∈t
∴a∈t'
∴a∪∈t'
∴(u,v)是a的安全邊
進一步證明以下推論:
∵切割(vc,v-vc)尊重集合a
又∵(u,v)是橫跨此切割的一條輕量級邊
∴由以上定理,(u,v)對a安全
prim演算法和kruskal演算法是對於這一推論的兩個應用形式。對於prim演算法,可以認為初始化時ga中的連通分量包括初始邊和剩下的n-2個點,ga中除了這個初始邊不斷變大,其他樹都是根節點狀態。每次迴圈加入一條和a相鄰的權值最小的邊,實際就是在森林ga中選乙個最近的根節點狀態的樹加入那個大樹中,直到所有點都加入為止。
通過如下方法將迷宮生成問題和求最小生成樹建立聯絡:
具體落實到程式設計上
讓迷宮全是牆.
選乙個單元格作為迷宮的通路,然後把它的鄰牆放入列表
當列表裡還有牆時
從列表裡隨機選乙個牆,如果這面牆分隔的兩個單元格只有乙個單元格被訪問過,那就從列表裡移除這面牆,即把牆打通,讓未訪問的單元格成為迷宮的通路,再把這個格仔的牆加入列表
如果牆兩面的單元格都已經被訪問過,那就從列表裡移除這面牆
列表裡已經沒有牆了,結束
三種迷宮生成演算法概述,這篇文章裡關於prim的描述我覺得更接近克魯斯卡爾演算法
三大迷宮生成演算法 ,這篇文章裡有示例**供參考
Prim迷宮演算法 隨機迷宮生成
最近在學android開發,老師讓我們自己做個應用,我就想做個簡單的roguelike rpg小遊戲。由於要用到迷宮,所以在網上學習了一下prim迷宮演算法,先用c 手擼了乙個簡單的模板。隨機選擇乙個白色格仔 i,j 實際位置為i 2 1,j 2 1 作為當前正在訪問的格仔,同時把該格仔放入乙個已經...
演算法 隨機生成迷宮
演算法原理 從起點開始,隨機選擇乙個方向移動,一直移動到終點,則移動的路徑便是迷宮的路徑。移動過程中要保證路徑不要相交,不要超出邊界,生成效果 public partial class mainform form void btncreateclick object sender,eventargs...
隨機生成迷宮
首先初始地圖所有位置均設為障礙牆,然後任意插入乙個牆體進牆佇列 再判斷此時牆體是否可以設定為路 判斷依據 上下左右四個位置是否只有乙個位置是路 若設定為路,則將該位置四周所有的牆插入佇列 若無法設定為路,直接從牆佇列中刪去當前結點所在的節點,若牆佇列不為空,則從佇列中隨機選取一處障礙重新執行,重複以...