最小生成樹Prim演算法和Kruskal演算法

2021-09-29 07:29:15 字數 3436 閱讀 5427

在學習最小生成樹演算法之前我們先了解一些基本概念

生成樹是乙個連通圖的連通子圖,包含圖中的n個點,n-1條邊。最小生成樹是這n-1條邊的權值之和最小的一顆生成樹。

prim演算法可在加權連通圖里搜尋最小生成樹,通俗來說就是在乙個帶權值的連通圖中保留n-1條邊(這n-1條邊的權值和最小),但依舊使這個圖為連通圖。prim演算法是基於貪心的思想,每次都選擇一條符合條件的權值最小的邊對於的點加入生成樹

prim演算法的時間複雜度為o(n^2),適合稠密圖

通常最小生成樹問題一般用鄰接矩陣存圖,比較方便

流程為:

首先初始化陣列dis【】、pre【】,dis【i】表示點 i 在生成樹中需要耗費的代價,dis = 0;pre【i】代表生成樹中pre【i】與點 i 相連(前驅),pre = -1,代表沒有前驅,vis【i】 = 1表示以訪問。id1

2345

6vis10

0000

dis061

5inf

infpre

- 1111

1 之後從上表中選乙個dis【】距離最小,且vis【】 = 0 的點,然後用這個點去更新他鄰接點(未訪問)在最小生成樹中的距離,且更新前驅,這裡的點為3

更新上表得id1

2345

6vis10

1000

dis051

564pre

- 1311

3選擇點6,更新其他點id1

2345

6vis10

1001

dis051

264pre

- 1316

3 接下來符合條件的點為4,更新其他陣列id1

2345

6vis10

1101

dis051

264pre

- 1316

3接下來選擇點2,更新資料id1

2345

6vis11

1101

dis051

234pre

- 1316

2接下來是點5,已更新完所有資料,dis【】陣列中衛最小生成樹的權值,pre【】陣列中記錄的是最小生成樹的邊

例題:hdu1102

#includeusing namespace std;

typedef pairpi;

const int inf = 0x3f7f7f7f;

const int n = 105;

int mp[n][n];

int lowcost[n];

int pre[n];

int vis[n];

int n;

int prim(int s)

vis[s] = 1;

pre[s] = -1;

for(int i = 1; i < n; i ++)

}if(pos == -1) return -1;

vis[pos] = 1;

ans += mmin;

for(int j = 1; j <= n; j ++)}}

return ans;

}int main()

printf("%d\n",prim(1));

/* for(int i = 2; i <= n; i ++)

}*/ return 0;

}//hdu1102

在學習這個演算法之前,我們需要先學習一種資料結構:並查集

並查集:.是一種關於集合的操作,能夠快速的找到某個元素所在的集合,而且還能夠實現集合之間的合併。

並查集包含三種操作:

1、初始化操作:最開始將每個元素出事化為乙個集合。pre【i】代表著i點所在的集合,最開始pre【i】 = i;

2、查詢元素所在的集合:也就是查詢這個集合所有元素的祖先

如pre【a】 = b,pre【b】 = c,pre【c】 = d,pre【d】 = d,這裡d就是所有元素的祖先

3、合併操作,合併兩個不同的集合,也就是找到這兩個集合的祖先,使其中乙個祖先指向另乙個集合。

並查集的優化:

這個圖中我們可以看出要找到點a的祖先,需要經過好幾次迴圈,那麼我就可以讓這個集合中的所有元素都直接指向祖先,這樣就可以在下次查詢時o(1)的複雜度就能夠找到。

關鍵**:

int findx(int x)

return x;

}void link(int u, int v)

kruskal演算法是基於貪心的思想,利用並查集實現的,每次選著一條權值最小的符合條件的邊(條件:這條邊的兩個點不再同乙個集合)將其加入生成樹集合

過程:1、將邊按權值大小排序

2、選擇一條權值最小的邊,且這條邊的兩點屬於不同的集合,然後合併這兩個集合

3、重複以上操作直到所有點都屬於乙個集合

例題:hdu1102

#includeusing namespace std;

typedef pairpi;

const int inf = 0x3f7f7f7f;

const int n = 200;

int mp[n][n];

int pre[n];

int n;

struct edge

grap[n*n];

bool cmp(edge a,edge b)

int findx(int x)

return x;

}void link(int u, int v)

int main()

int cnt = 0;

for(int i = 1; i<= n*n; i ++)

}for(int i = 1; i <= n; i ++)

pre[i] = i;

sort(grap,grap+cnt,cmp);

int ans = 0;

for(int i = 0; i < cnt; i ++)

}printf("%d\n",ans);

}return 0;

}//hdu 1102

最小生成樹(prim演算法)

最小生成樹是資料結構中圖的一種重要應用,它的要求是從乙個帶權無向完全圖中選擇n 1條邊並使這個圖仍然連通 也即得到了一棵生成樹 同時還要考慮使樹的權最小。prim演算法要點 設圖g v,e 其生成樹的頂點集合為u。把v0放入u。在所有u u,v v u的邊 u,v e中找一條最小權值的邊,加入生成樹...

最小生成樹 Prim演算法

prim 演算法 以領接矩陣儲存 圖g bool b i 表示頂點i是否被訪問,初始化時候memset b,false,sizeof b b 0 value,表示從第0個節點開始。用value i 表示節點i到最小生成樹a中定點的最小距離。例如value 1 a 0 1 int sum記錄權值和 i...

最小生成樹 prim 演算法

一 演算法描述 假設存在連通帶權圖g v,e 其中最小生成樹為t,首先從圖中隨意選擇一點s屬於v作為起始點,並將其標記後加入集合u 中。然後演算法重複執行操作為在所有v屬於u,u屬於v u的邊 v0,u0 屬於e中找一條代價最小的邊並加入集合t,同時將u0併入u,直到u v為止。這是,t中必有n 1...