① 最小生成樹的兩種演算法
主要有兩個:
1.普里姆(Prim)演算法
特點:時間復雜度為O(n2).適合於求邊稠密的最小生成樹。
2.克魯斯卡爾(Kruskal)演算法
特點:時間復雜度為O(eloge)(e為網中邊數),適合於求稀疏的網的最小生成樹。
② 克魯斯卡爾演算法是求圖的什麼
求圖的最小生成樹啊,你上面不是也講了么?
求最小生成樹還有另一種prim演算法
prim適合用於稠密圖,kruskal適合用於稀疏圖
兩種演算法都是以貪心為基本思想的~
滿意望採納謝謝!!!!
③ sh實現最小生成樹和最短路徑的演算法
圖的最小生成樹與最短路徑的演算法
一、圖的生成樹與最小生成樹
在一個連通圖G中,如果取它的全部頂點和一部分邊構成一個子圖G』,即:
若邊集E(G』)中的邊既將圖中的所有頂點連通又不形成迴路,則稱子圖G』是原圖G的一棵生成樹。
最小生成樹:給圖中每個邊賦一權值,所有生成樹中所選擇邊的權值之和最小的生成樹,稱之為最小代價生成樹,即是最小生成樹。
1、普里姆演算法
1.1演算法描述
假設G=(V, E)是一個具有n個頂點的連通網,T=(U, TE)是G的最小生成樹,其中U是T的頂點集,TE是T的邊集,U和TE的初值均為空集。演算法開始時,首先從V中任取一個頂點(假定取v1),將它並入U中,此時U={v1},然後只要U是V的真子集(即),就從那些其一個端點已在T中,另一個端點仍在T外的所有邊中,找一條最短(即權值最小)邊,假定為(vi, vj),其中,並把該邊(vi, vj)和頂點vj分別並入T的邊集TE和頂點集U,如此進行下去,每次往生成樹里並入一個頂點和一條邊,直到(n-1)次後就把所有n個頂點都並入到生成樹T的頂點集中,此時U=V,TE中含有(n-1)條邊,T就是最後得到的最小生成樹。 1.2關鍵問題
普里姆演算法的關鍵之處是:每次如何從生成樹T中到T外的所有邊中,找出一條最短邊。例如,在第k次前,生成樹T中已有k個頂點和(k-1)條邊,此時T中到T外的所有邊數為k(n-k),當然它包括兩頂點間沒有直接邊相連,其權值被看作為「無窮大」的邊在內,從如此多的邊中查找最短邊,其時間復雜性為O(k(n-k)),顯然是很費時的。是否有一種好的方法能夠降低查找最短邊的時間復雜性呢? 1.3 解決方法
方法是:假定在進行第k次前已經保留著從T中到T外每一頂點(共(n-k)個頂點)的各一條最短邊,進行第k次時,首先從這(n-k)條最短邊中,找出一條最最短的邊(它就是從T中到T外的所有邊中的最短邊),假設為(vi, vj),此步需進行(n-k)次比較;然後把邊(vi, vj)和頂點vj分別並入T中的邊集TE和頂點集U中,此時T外只有n-(k+1)個頂點,對於其中的每個頂點vt,若(vj, vt)邊上的權值小於已保留的從原T中到vt的最短邊的權值,則用(v, vt)修改之,使從T中到T外頂點vt的最短邊為(vj, vt),否則原有最短邊保持不變,這樣,就把第k次後從T中到T外每一頂點vt的各一條最短邊都保留下來了。為進行第(k+1)次運算做好了准備,此步需進行(n-k-1)次比較。所以,利用此方法求第k次的最短邊共需比較2(n-k)-1次,即時間復雜性為O(n-k)。
1.4 prim演算法:
設一個輔助數組closedge,以記錄從U到V—U具有最小代價的邊。數組中的每個元素closedge[v]是記錄類型,包含兩個域: closedge[v].lowcast=Min{cost(u,v)|u∈U}; closedge[v].vex存儲該邊依附的在U中的頂點。
proc mintree_prim(gn:adjmatrix;u0:integer);
begin
for v:=1 to n do
if v<>u0 then
with closedage[v] do [vex:=u0; lowcast:=gn[u0,v];]
closedge[u0].lowcast:=0;{並入U集合}
for i:=1 to n-1 do
begin
v:=min(closedge);{尋找代價最小的邊}
write(closedge[v].vex,v); closedge[v].lowcast:=0;{並入U集合}
for k:=1 to n do
if gn[v,k]<closedge[k].lowcast then
begin closedge[k].lowcast:=gn[v,k]; closedge[k].vex:=v; end;
end;
end; 練習1:prim演算法實現
【問題描述】從文件中讀入連通帶權圖的信息,按prim演算法求出該圖的最小生成樹,以V1作為初始結點。
【輸入文件】第一行兩個整數m和n,分別表示圖的結點數和圖中的邊數。以下n行表示n條邊:每一行三個數x、y和k,k表示x與y之間邊的權值。
【輸出文件】共m行,第一行:最小生成樹的權;以下m-1行表示選取的邊,邊的第1個結點小於第2個結點,並按結點由小到大輸出。
【示例】輸入:5 7 輸出:45
1 2 17 1 4
2 3 30 1 5
1 4 5 2 4
2 4 10 3 5
3 4 24
3 5 7
1 5 23
練習2: Eddy painting
Eddy begins to like painting pictures recently ,he is sure of himself to become a painter.Every day Eddy draws pictures in his small room, and he usually puts out his newest pictures to let his friends appreciate. but the result it can be imagined, the friends are not interested in his picture.Eddy feels very puzze,in order to change all friends 's view to his technical of painting pictures ,so Eddy creates a problem for the his friends of you.
Problem descriptions as follows: Given you some coordinates pionts on a drawing paper, every point links with the ink with the straight line, causes all points finally to link in the same place. How many distants does your ty discover the shortest length which the ink draws?
Input:
The first line contains 0 < n <= 100, the number of point. For each point, a line follows; each following line contains two real numbers indicating the (x,y) coordinates of the point.
Input contains multiple test cases. Process to the end of file.
Output:
Your program prints a single real number to two decimal places: the minimum total length of ink lines that can connect all the points.
Sample Input:
3
1.0 1.0
2.0 2.0
2.0 4.0
Sample Output:
3.41
2、克魯斯卡爾演算法
2.1 演算法描述
假設G=(V,E)是一個具有n個頂點的連通網,T=(U,TE)是G的最小生成樹,U的初值等於V,即包含有G中的全部頂點,TE的初值為空。此演算法的基本思想是,將圖G中的邊按權值從小到大的順序依次選取,若選取的邊使生成樹T不形成迴路,則把它並入TE中,保留作為T的一條邊,若選取的邊使生成樹T形成迴路,則將其舍棄,如此進行下去,直到TE中包含有n-1條邊為止。此時的T即為最小生成樹。
2.2 關鍵問題
克魯斯卡爾演算法的關鍵之處是:如何判斷欲加入的一條邊是否與生成樹中已選取的邊形成迴路。這可將各頂點劃分為所屬集合的方法來解決,每個集合中的頂點表示一個無迴路的連通分量。演算法開始時,由於生成樹的頂點集等於圖G的頂點集,邊集為空,所以n個頂點分屬於n個集合。每個集合中只有一個頂點,表明頂點之問互不連通。
2.3 Kruskal演算法:
proc mintree_krusk(gn:adjmatrix);
begin
for i:=1 to n do
un[i]:=i;
for i:=1 to n-1 do
begin
minedge(a,b);
write(a,b,gn[a,b]);
k:=un[b];
for i:=1 to n do {兩個連通分量合並}
if un[i]=k then un[i]:=un[a];
end;
end;
2.4 注意:
proc minedge(var a:integer;var b:integer);用於在剩下的邊中選取不再同一連通分量上的最小代價的邊,邊的結點分別為a和b。
為了實現該過程,可以將圖中的邊生成一邊結點(包含兩個頂點和代價)數組,由小到大排序,然後通過排序後的數組進行處理;
un數組:用來記載隨著邊的加入,各頂點屬於哪個連通分量。
練習3:Kruskal演算法實現
【問題描述】從文件中讀入連通帶權圖的信息,按Kruskal演算法求出該圖的最小生成樹,以V1作為初始結點。
【輸入文件】第一行兩個整數m和n,分別表示圖的結點數和圖中的邊數。以下n行表示n條邊:每一行三個數x、y和k,k表示x與y之間邊的權值。
【輸出文件】共m行,第一行:最小生成樹的權;以下m-1行表示選取的邊,按選取邊的權值由小到大輸出。
【示例】輸入:5 7 輸出:45
1 2 17 1 4
2 3 30 3 5
1 4 5 2 4
2 4 10 1 5
3 4 24
3 5 7
1 5 23
練習4:判斷最小生成樹是否唯一
Given a connected undirected graph, tell if its minimum spanning tree is unique.
Definition 1 (Spanning Tree): Consider a connected, undirected graph G = (V, E). A spanning tree of G is a subgraph of G, say T = (V', E'), with the following properties:
1. V' = V.
2. T is connected and acyclic.
Definition 2 (Minimum Spanning Tree): Consider an edge-weighted, connected, undirected graph G = (V, E). The minimum spanning tree T = (V, E') of G is the spanning tree that has the smallest total cost. The total cost of T means the sum of the weights on all the edges in E'.
Input
The first line contains a single integer t (1 <= t <= 20), the number of test cases. Each case represents a graph. It begins with a line containing two integers n and m (1 <= n <= 100), the number of nodes and edges. Each of the following m lines contains a triple (xi, yi, wi), indicating that xi and yi are connected by an edge with weight = wi. For any two nodes, there is at most one edge connecting them.
Output
For each input, if the MST is unique, print the total cost of it, or otherwise print the string 'Not Unique!'.
Sample Input
2
3 3
1 2 1
2 3 2
3 1 3
4 4
1 2 2
2 3 2
3 4 2
4 1 2
Sample Output
3
Not Unique!
二、最短路徑
【問題描述】由於從一頂點到另一頂點可能存在著多條路徑。每條路徑上所經過的邊數可能不同,即路徑長度不同,我們把路徑長度最短(即經過的邊數最少)的那條路徑叫做最短路徑,其路徑長度叫做最短路徑長度或最短距離。求圖中一頂點vi到其餘各頂點的最短路徑和最短距離比較容易,只要從該頂點vi,出發對圖進行一次廣度優先搜索遍歷,在遍歷時記下每個結點的層次即可。
若圖是帶權圖(假定權值非負)從源點vi到終點vj的每條路徑上的權(它等於該路徑上所經邊上的權值之和,稱為該路徑的帶權路徑長度)可能不同,我們把權值最小的那條路徑也稱做最短路徑,其權值也稱作最短路徑長度或最短距離。
實際上,這兩類最短路徑問題可合並為一類,這只要把第一類的每條邊的權都設為1就歸屬於第二類了,所以在以後的討論中,若不特別指明,均是指第二類的最短路徑問題。
求圖的最短路徑問題包括兩個子問題:一是求圖中一頂點到其餘各頂點的最短路徑,二是求圖中每對頂點之間的最短路徑。下面分別進行討論。
始點 終點 最短路徑 路徑長度
v0 v1 No path
v2 (v0,v2) 10
v3 (v0,v4,v3) 50
v4 (v0,v4) 30
v5 (v0,v4,v3,v5) 60
始點 終點 最短路徑 路徑長度
v1 V2 (v1,v2) 10
V3 (v1,v2,v3) 27
V4 (v1,v5,v4) 20
v5 (v1,v5) 7
1、從一頂點到其餘各頂點的最短路徑
1.1 描述
迪傑斯特拉(Dijkstra)於1959年提出了解決此問題的一般演算法,具體做法是按照從源點到其餘每一頂點的最短路徑長度的升序依次求出從源點到各頂點的最短路徑及長度,每次求出從源點vi到一個終點vj的最短路徑及長度後,都要以vj作為新考慮的中間點,用vi到vj的最短路徑和最短路徑長度對vi到其它尚未求出最短路徑的那些終點的當前路徑及長度作必要的修改,使之成為當前新的最短路徑和最短路徑長度,當進行n-2次後演算法結束。
1.2 Dijkstra演算法:
首先,引進一個輔助向量dist,dist[i]表示當前所找到的從始點V到每個終點Vi的最短路徑長度。其初態為:若<v,vi>存在,則dist[i]為其上的權值,否則為最大值(計算機能表示)。
演算法:(1)用鄰接矩陣cost表示帶權有向圖。S表示已找到的從v出發的最短路徑的終點的集合,初態為空。dist向量的初值為:dist[v,i]=cost[v,i];
(2)選擇vj,使得:dist[j]=Min{dist[i]|vi∈V-S};vj就是當前求得從v出發的最短路徑的終點。
S=S+{j};
(3)修改從v出發到集合V-S上任意頂點vk可達的最短路徑長度。
if dist[j]+cost[j,k]<dist[k] then dist[k]:=dist[j]+cost[j,k];
(4)重復(2)(3)共n-1次。
代碼:proc short_dij;
begin
for i:=1 to n do
begin
dist[i]:=cost[v0,i];
if dist[i]<max then path[i]:=v0 else path[i]:=-1; end;
flag[I]:=true;
for k:=1 to n-1 do
begin
wm:=max; j:=v0;
for i:=1 to n do
if not(flag[i]) and (dist[i]<wm) then begin j:=i; m:=dist[i]; end;
flag[j]:=true; for i:=1 to n do if not(flag[i]) and (dist[j]+cost[j,i]<dist[i]) then
begin dist[i]:=dist[j]+cost[j,i]; path[i]:=j; end;
end;
end; 其中:cost:鄰接矩陣;
path[i]:存儲從v0到頂點i的最短路徑;是以集合作為數組元素;
dist[i]:存儲相應路徑長度;
flag[i]:表示已處理的頂點。
練習5:Dijkstra演算法練習
【問題描述】從文件中讀入帶權圖的信息,按Dijkstra演算法根據給定源點求出從源點法到該圖中其餘頂點的最短路徑。
【輸入文件】第一行:一個整數L:L=0表示無向圖,L=1表示有向圖;第二行三個整數m、n和k,分別表示圖的結點數、圖中的邊數以及源點。以下n行表示n條邊:每一行三個數x、y和z,z表示x與y之間邊的權值。
【輸出文件】共m-1行,每一行的數據包括:頂點: 最短路徑:路徑,如果不存在路徑,數據為:頂點:No path。
【示例】輸入:1 輸出:2:No path
6 8 1 3:10:1 3
1 3 10 4:50:1 5 4
1 5 30 5:30:1 5
1 6 100 6:60:1 5 4 6
2 3 5
3 4 50
4 6 10
5 4 20
5 6 60
練習6:路由選擇問題
【問題描述】
X城有一個含有N個節點的通信網路,在通信中,我們往往關心信息從一個節點I傳輸到節點J的最短路徑。遺憾的是,由於種種原因,線路中總有一些節點會出故障,因此在傳輸中要避開故障節點。
任務一:在己知故障節點的情況下,求避開這些故障節點,從節點I到節點J的最短路徑S0。
任務二:在不考慮故障節點的情況下,求從節點I到節點J的最短路徑S1、第二最短路徑S2。
【輸入文件】
第1行: N I J (節點個數 起始節點 目標節點)
第2—N+1行: Sk1 Sk2…SkN (節點K到節點J的距離為SkJ K=1,2,……,N)
最後一行: P T1 T2……Tp (故障節點的個數及編號)
【輸出文件】
S0 S1 S2 (S1<=S2 從節點I到節點J至少有兩條不同路徑)
【輸入輸出樣例】
route.in
5 1 5
0 10 5 0 0
10 0 0 6 20
5 0 0 30 35
0 6 30 0 6
0 20 35 6 0
1 2
route.out
40 22 30
2、每對頂點之間的最短路徑
求圖中每對頂點之間的最短路徑是指把圖中任意兩個頂點vi和vj(i≠j)之間的最短路徑都計算出來。解決此問題有兩種方法:一是分別以圖中的每個頂點為源點共調用n次迪傑斯特拉演算法,此方法的時間復雜性為O(n3);二是採用下面介紹的弗洛伊德(Floyed)演算法,此演算法的時間復雜性仍為O(n3),但比較簡單。 弗洛伊德演算法實際上是一個動態規劃的演算法。從圖的鄰接矩陣開始,按照頂點v1,v2,…,vn的次序,分別以每個頂點vk(1≤k≤n)作為新考慮的中間點,在第k-1次運算Ak-1 (A(0)為原圖的鄰接矩陣G) 的基礎上,求出每對頂點vi到vj的最短路徑長度計算公式為:
Floyd演算法:
proc shortpath_floyd;
begin
for i:=1 to n do for j:=1 to n do
begin
length[i,j]:=cost[i,j];
if length[i,j]<max then path[i,j]:=[i]+[j];
end;
for k:=1 to n do for i:=1 to n do for j:=1 to n do
if length[i,k]+length[k,j]<length[i,j] then
begin
length[i,j]:=length[i,k]+length[k,j];
path[i,j]:=path[i,k]+path[k,j];
end;
end;
其中:cost為鄰接矩陣;
path[i,j]:表示頂點i到j的最短路徑;
length[i,j]:
練習7:Floyd演算法練習
【問題描述】從文件中讀入帶權圖的信息,按Dijkstra演算法根據給定源點求出從源點到該圖中其餘頂點的最短路徑。
【輸入文件】第一行:一個整數L:L=0表示無向圖,L=1表示有向圖;第二行三個整數m、n,分別表示圖的結點數和圖中的邊數。以下n行表示n條邊:每一行三個數x、y和z,z表示x與y之間邊的權值。第n+2行:整數R,以下R行每行一個整數表示頂點標號作為源點。
【輸出文件】共R行,每一行的數據表示源點到其餘頂點的距離,按頂點編號由小大輸出,如果沒有路徑,輸出-1。
【示例】輸入:1 輸出:-1 10 50 30 60
6 8 -1 –1 –1 20 30
1 3 10
1 5 30
1 6 100
2 3 5
3 4 50
4 6 10
5 4 20
5 6 60
2
1
5