最小生成樹的性質
MST性質:設G = (V,E)是連通帶權圖,U是V的真子集。如果(u,v)∈E,且u∈U,v∈V-U,且在所有這樣的邊中,
(u,v)的權c[u][v]最小,那麼一定存在G的一棵最小生成樹,(u,v)為其中一條邊。
構造最小生成樹,要解決以下兩個問題:
(1).盡可能選取權值小的邊,但不能構成回路(也就是環)。
(2).選取n-1條恰當的邊以連接網的n個頂點。
設G = (V,E)是連通帶權圖,V = {1,2,…,n}。先任選一點(一般選第一個點),首先置S = {1},然後,只要S是V的真子集,就選取滿足條件i ∈S,j ∈V-S,且c[i][j]最小的邊,將頂點j添加到S中。這個過程一直進行到S = V時為止。在這個過程中選取到的所有邊恰好構成G的一棵最小生成樹。
以 hdu 1863為例 (點擊打開鏈接)
以 hdu 1863為例 (點擊打開鏈接)
注:若頂點數為n,邊為e
prim算法適合稠密圖,其時間復雜度為O(n^2),其時間復雜度與邊的數目無關,
而kruskal算法的時間復雜度為O(eloge)跟邊的數目有關,適合稀疏圖。
V: {1,2,3,4,5,6,7}E: {a:(1,2):50, b:(1,3):60, c:(2,4):65, d:(2,5):40, e:(3,4):52, f:(3,7):45, g:(4,5):50, h:(4,6):30, i:(4,7):42, j:(5,6):70}kruskal
0: V={{1},{2},{3},{4},{5},{6},{7}}, E={}, pick 1st from {h,d,i,f,a,g,e,b,c,j}1: V={{1},{2},{3},{4,6},{5},{7}}, E={h}, pick 1st from {d,i,f,a,g,e,b,c,j}2: V={{1},{2,5},{3},{4,6},{7}}, E={h,d}, pick 1st from {i,f,a,g,e,b,c,j}3: V={{1},{2,5},{3},{4,6,7}}, E={h,d,i}, pick 1st from {f,a,g,e,b,c,j}4: V={{1},{2,5},{3,4,6,7}}, E={h,d,i,f}, pick 1st from {a,g,b,c,j}5: V={{1,2,5},{3,4,6,7}}, E={h,d,i,f,a}, pick 1st from {g,b,c,j}6: V={{1,2,5,3,4,6,7}}, E={h,d,i,f,a,g}, pick 1st from {}#: final V={1,2,5,3,4,6,7}, E={h,d,i,f,a,g}prim
Vstart = 10: V={1}, E={}, pick 1st from {a,b}1: V={1,2}, E={a}, pick 1st from {d,b,c}2: V={1,2,5}, E={a,d}, pick 1st from {g,b,c,j}3: V={1,2,5,4}, E={a,d,g}, pick 1st from {h,i,e,b}4: V={1,2,5,4,6}, E={a,d,g,h}, pick 1st from {i,e,b}5: V={1,2,5,4,6,7}, E={a,d,g,h,i}, pick 1st from {e,b}6: V={1,2,5,4,6,7,3}, E={a,d,g,h,i,e}.
Kruskal算法:
void Kruskal(Edge E[],int n,int e)
{
int i,j,m1,m2,sn1,sn2,k;
int vset[MAXE];
for (i=0;i<n;i++) vset[i]=i; //初始化輔助數組
k=1; //k表示當前構造最小生成樹的第幾條邊,初值為1
j=0; //E中邊的下標,初值為0
while (k<n) //生成的邊數小於n時循環
{
m1=E[j].u;m2=E[j].v; //取一條邊的頭尾頂點
sn1=vset[m1];sn2=vset[m2]; //分別得到兩個頂點所屬的集合編號
if (sn1!=sn2) //兩頂點屬於不同的集合,該邊是最小生成樹的一條邊
{
printf(" (%d,%d):%d/n",m1,m2,E[j].w);
k++; //生成邊數增1
for (i=0;i<n;i++) //兩個集合統一編號
if (vset[i]==sn2) //集合編號為sn2的改為sn1
vset[i]=sn1;
}
j++; //掃描下一條邊
}
}
Prim算法:
void prim(MGraph g,int v)
{
int lowcost[MAXV],min,n=g.vexnum;
int closest[MAXV],i,j,k;
for (i=0;i<n;i++) //給lowcost[]和closest[]置初值
{
lowcost[i]=g.edges[v][i];
closest[i]=v;
}
for (i=1;i<n;i++) //找出n-1個頂點
{
min=INF;
for (j=0;j<n;j++) //在(V-U)中找出離U最近的頂點k
if (lowcost[j]!=0 && lowcost[j]<min)
{
min=lowcost[j];k=j;
}
printf(" 邊(%d,%d)權為:%d/n",closest[k],k,min);
lowcost[k]=0; //標記k已經加入U
for (j=0;j<n;j++) //修改數組lowcost和closest
if (g.edges[k][j]!=0 && g.edges[k][j]<lowcost[j])
{
lowcost[j]=g.edges[k][j];closest[j]=k;
}
}
}...余下全文>>