標籤:9.png src idt int a演算法 指定 個人 最短路徑 ***
圖的最佳化問題:最小產生樹、最短路徑
典型的圖應用問題
無向連通加權圖的最小產生樹
有向/無向加權圖的最短路徑
四個經典演算法
Kruskal演算法、Prim演算法---------------最小產生樹
Dijkstra演算法、Floyd演算法-------------最短路徑
最小產生樹的概念:
G=(V,E):無向連通加權圖
C(e)或C(v,w): 邊e=(v,w)的耗費(Cost)
若S=(V,T)是G的一棵產生樹(T是樹邊集),那麼, S的邊長之和稱作產生樹S的耗費C(S)
耗費C(S)達到最小值的產生樹S,稱為G的最小耗費產生樹,也稱最小產生樹(MinimumSpanningTree)
即C(S)≤C(S‘) (S‘是圖G的任一產生樹)
注意:最小產生樹可能不唯一
Kruskal演算法
演算法思想: 按長度從小到大的依次把邊加進產生樹,若添加某邊後形成了迴路,就捨棄這條邊
反覆如此,直到選出n-1條邊,便得到最小產生樹.。
通俗來講,該演算法很簡單。
步驟:
1.在空白處畫出與原圖一模一樣的結點位置。(只畫結點,權不需要,結點的位置要一模一樣)。
2.按權畫邊。從權值最小的開始,,從4開始,草圖就連A-B,到權值5,就連B-F,到權值6,此時就會發現,如果串連A-F,那麼A-B-F就會構成一個完整的迴路(從任意一點出發可以回到原點。)。因此,就要捨去權值6,即邊A-F不可串連。。。。。依次按權大小畫其他邊。直到最後一個結點。
Kruskal演算法偽程式形式
void Kruskal(***) //***表示函數要求的參數
{ int et=0; //et用於記錄選中的邊數
置樹邊集T為空白;
while(et<n-1) //n是圖中的頂點數
{ 從G中選出當前最短邊(v,w);
if(添此邊於T中,不使產生樹產生迴路)
{ 把(v,w)加進T;et++;}
else 捨棄(v,w);
}
}
實現方法分析:
子樹合并法描述和樣本
描述:
Kruskal演算法的子樹合并法描述形式:
方法一:
void Kruskal(***) //***表示函數要求的參數
{ int et=0;
每個頂點自成一個集合,並指定集合名;
while(et<n-1)
{ 從G中選出當前最短邊(v,w);
找到v所在的集合名i,和w所在的集合名j;
if(i!=j)
{ 把(v,w)加進T; et++;
將集合i與集合j合并成一個集合k; }
}
}
方法二:
void Kruskal(***) //***表示函數要求的參數
{ int et=0;
每個頂點一個集合,並指定集合名 ;
while(et<n-1)
{ 從G中選出當前最短邊(v,w);
if(v和w不在同一子樹中)
{ 把(v,w)加進T;et++;
將v所在的子樹與w所在的子樹合并成一棵子樹;
}
}
}
結論:無論是按權畫邊法,還是子樹合并法都是可以找出最小產生樹,但是個人認為按權畫邊法比較容易理解。
23最小產生樹之Kruskal演算法