最小生成樹詳解 prim+ kruskal程式碼模板
最小生成樹概念:
一個有 n 個結點的連通圖的生成樹是原圖的極小連通子圖,且包含原圖中的所有 n 個結點,並且有保持圖連通的最少的邊。 最小生成樹可以用kruskal(克魯斯卡爾)演算法或prim(普里姆)演算法求出。最小生成樹其實是最小權重生成樹的簡稱。
prim:
概念:普里姆演算法(Prim演算法),圖論中的一種演算法,可在加權連通圖裡搜尋最小生成樹。意即由此演算法搜尋到的邊子集所構成的樹中,不但包括了連通圖裡的所有頂點
圖例 | 說明 | 不可選 | 可選 | 已選(Vnew) |
---|---|---|---|---|
此為原始的加權連通圖。每條邊一側的數字代表其權值。 | - | - | - | |
|
頂點D被任意選為起始點。頂點A、B、E和F通過單條邊與D相連。A是距離D最近的頂點,因此將A及對應邊AD以高亮表示。 | C, G | A, B, E, F | D |
下一個頂點為距離D或A最近的頂點。B距D為9,距A為7,E為15,F為6。因此,F距D或A最近,因此將頂點F與相應邊DF以高亮表示。 | C, G | B, E, F | A, D | |
演算法繼續重複上面的步驟。距離A為7的頂點B被高亮表示。 | C | B, E, G | A, D, F | |
在當前情況下,可以在C、E與G間進行選擇。C距B為8,E距B為7,G距F為11。E最近,因此將頂點E與相應邊BE高亮表示。 | 無 | C, E, G | A, D, F, B | |
這裡,可供選擇的頂點只有C和G。C距E為5,G距E為9,故選取C,並與邊EC一同高亮表示。 | 無 | C, G | A, D, F, B, E | |
頂點G是唯一剩下的頂點,它距F為11,距E為9,E最近,故高亮表示G及相應邊EG。 | 無 | G | A, D, F, B, E, C | |
現在,所有頂點均已被選取,圖中綠色部分即為連通圖的最小生成樹。在此例中,最小生成樹的權值之和為39。 | 無 | 無 | A, D, F, B, E, C, G |
演算法模板:
#include<stdio.h> #include<string.h> #include <iostream> #include<bits/stdc++.h> #define IO ios::sync_with_stdio(false);\ cin.tie(0);\ cout.tie(0); #define MAX 0x3f3f3f3f using namespace std; int logo[1010];//用來標記0和1 表示這個點是否被選擇過 int map1[1010][1010];//鄰接矩陣用來儲存圖的資訊 int dis[1010];//記錄任意一點到這個點的最近距離 int n;//點個數 int prim() { int i,j,now; int sum=0; /*初始化*/ for(i=1; i<=n; i++) { dis[i]=MAX; logo[i]=0; } /*選定1為起始點,初始化*/ for(i=1; i<=n; i++) { dis[i]=map1[1][i]; } dis[1]=0; logo[1]=1; /*迴圈找最小邊,迴圈n-1次*/ for(i=1; i<n; i++) { now=MAX; int min1=MAX; for(j=1; j<=n; j++) { if(logo[j]==0&&dis[j]<min1) { now=j; min1=dis[j]; } } if(now==MAX) break;//防止不成圖 logo[now]=1; sum+=min1; for(j=1; j<=n; j++)//添入新點後更新最小距離 { if(logo[j]==0&&dis[j]>map1[now][j]) dis[j]=map1[now][j]; } } if(i<n) printf("?\n"); else printf("%d\n",sum); } int main() { while(scanf("%d",&n),n)//n是點數 { int m=n*(n-1)/2;//m是邊數 memset(map1,0x3f3f3f3f,sizeof(map1));//map是鄰接矩陣儲存圖的資訊 for(int i=0; i<m; i++) { int a,b,c; scanf("%d%d%d",&a,&b,&c); if(c<map1[a][b])//防止重邊 map1[a][b]=map1[b][a]=c; } prim(); } }
Kruskal演算法:
1.概覽
Kruskal演算法是一種用來尋找最小生成樹的演算法,在剩下的所有未選取的邊中,找最小邊,如果和已選取的邊構成迴路,則放棄,選取次小邊。
2.實現過程
1).記Graph中有v個頂點,e個邊
2).新建圖Graphnew,Graphnew中擁有原圖中相同的e個頂點,但沒有邊
3).將原圖Graph中所有e個邊按權值從小到大排序
4).迴圈:從權值最小的邊開始遍歷每條邊 直至圖Graph中所有的節點都在同一個連通分量中 if 這條邊連線的兩個節點於圖Graphnew中不在同一個連通分量中 新增這條邊到圖Graphnew中
圖例描述:
首先第一步,我們有一張圖Graph,有若干點和邊
將所有的邊的長度排序,用排序的結果作為我們選擇邊的依據。這裡再次體現了貪心演算法的思想。資源排序,對區域性最優的資源進行選擇,排序完成後,我們率先選擇了邊AD。這樣我們的圖就變成了下圖
在剩下的變中尋找。我們找到了CE。這裡邊的權重也是5
依次類推我們找到了6,7,7,即DF,AB,BE。
下面繼續選擇, BC或者EF儘管現在長度為8的邊是最小的未選擇的邊。但是現在他們已經連通了(對於BC可以通過CE,EB來連線,類似的EF可以通過EB,BA,AD,DF來接連)。所以不需要選擇他們。類似的BD也已經連通了(這裡上圖的連通線用紅色表示了)。最後就剩下EG和FG了。當然我們選擇了EG。
程式碼:
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; int n, m,sum; struct node { int start,end,power;//start為起始點,end為終止點,power為權值 } edge[5050]; int pre[5050]; int cmp(node a, node b) { return a.power<b.power;//按照權值排序 } int find(int x)//並查集找祖先 { if(x!=pre[x]) { pre[x]=find(pre[x]); } return pre[x]; } void merge(int x,int y,int n)//並查集合並函式,n是用來記錄最短路中應該加入哪個點 { int fx=find(x); int fy=find(y); if(fx!=fy) { pre[fx]=fy; sum+=edge[n].power; } } int main() { while(~scanf("%d", &n), n)//n是點數 { sum=0; m=n*(n-1)/2;//m是邊數,可以輸入 int i; int start,end,power; for(i=1; i<=m; i++) { scanf("%d %d %d", &start, &end, &power); edge[i].start=start,edge[i].end=end,edge[i].power=power; } for(i=1; i<=m; i++) { pre[i]=i; }//並查集初始化 sort(edge+1, edge+m+1,cmp); for(i=1; i <= m; i++) { merge(edge[i].start,edge[i].end,i); } printf("%d\n",sum); } return 0; }
相關推薦
最小生成樹詳解 prim+ kruskal程式碼模板
最小生成樹概念: 一個有 n 個結點的連通圖的生成樹是原圖的極小連通子圖,且包含原圖中的所有 n 個結點,並且有保持圖連通的最少的邊。 最小生成樹可以用kruskal(克魯斯卡爾)演算法或prim(普里姆)演算法求出。最小生成樹其實是最小權重生成樹的簡稱。 prim: 概念:普里姆演算法(Prim演算法),
Prim演算法生成最小生成樹詳解
建立一個low陣列代表相應每個節點連線所需最小費用,一個vis陣列標記相應節點是否連線過。low陣列的初始值用節點1到其餘各點的費用來填充如該圖所示low陣列的初始值應該為:06345以上便是1號節點對於其他各點的費用接下來在low陣列中尋找最小值 為3號節點費用為3最小。
最小生成樹MST(Prim/Kruskal模版)
生成樹:如果連通圖G的一個子圖是一棵包含G的所有頂點的樹,則該子圖稱為G的生成樹。生成樹不唯一,不同起點遍歷所得生成樹不同。 最小生成樹:邊權最小的生成樹。 最小邊原則:圖中權值最小的邊(如果唯一的話)一定在最小生成樹上。 唯一性:一棵生成樹上,如果各邊的
每日一省之————加權無向圖的最小生成樹演算法(Prim/Kruskal演算法)
1.帶權重的邊的資料結構 /** * 該類物件可以表示圖中的一條邊 * @author lhever 2017年2月19日 下午5:10:49 * @version v1.0 */ public class Edge implements Com
最小生成樹詳解
最小生成樹概念: 一個有 n 個結點的連通圖的生成樹是原圖的極小連通子圖,且包含原圖中的所有 n 個結點,並且有保持圖連通的最少的邊。 最小生成樹可以用kruskal(克魯斯卡爾)演算法或prim(普里姆)演算法求出。最小生成樹其實是最小權重生成樹的簡稱。 prim:
次小生成樹詳解及模板(prim 以及 kruskal)
寫在前面我們大部分都對最小生成樹瞭解的多一些,一般求最小生成樹的演算法是prim、kurskal,那麼對於次小生成樹,我們也可以用上面兩種演算法來求解演算法解釋這兩種演算法的思路都是相同的,首先求出最小生成樹,我們列舉每條不在最小生成樹上的邊,並把這條邊放到最小生成樹上面,然
無向帶權圖的最小生成樹算法——Prim及Kruskal算法思路
下一個 必須 循環 算法與數據結構 最小值 邊集 當前 知識 所有 邊賦以權值的圖稱為網或帶權圖,帶權圖的生成樹也是帶權的,生成樹T各邊的權值總和稱為該樹的權。 最小生成樹(MST):權值最小的生成樹。 生成樹和最小生成樹的應用:要連通n個城市需要n-1條邊線路
最小生成樹算法:Kruskal算法 Prim算法
ont 進行 != 路徑 最小 tmp inf init 標識 定義 對於連通的無向圖G(V,E),如果一個E的無環子集T,可以連接所有節點,並且又具有最小權重,稱樹g(V,T)為圖G(V,E)的最小生成樹。 概念 偽代碼 Kruskal算法和Prim算法均使用貪心策略實
最小生成樹構造演算法--Prim演算法,Kruskal演算法(C語言)
最小生成樹 最小生成樹(minimum spanning tree)是由n個頂點,n-1條邊,將一個連通圖連線起來,且使權值最小的結構。 最小生成樹可以用Prim(普里姆)演算法或kruskal(克魯斯卡爾)演算法求出。 我們將以下面的帶權連通圖為例講解這
[XOR最小生成樹 分治 Trie || Prim 堆] BNUOJ 52318 Be Friends
#include<cstdio> #include<cstdlib> #include<algorithm> #include<queue> using namespace std; typedef long long ll; inline char nc()
最小生成樹(1)--Kruskal演算法
圖的最小生成樹 圖的最小生成樹,是指用最小的邊讓圖連通,讓任意兩點之間可以互相到達。圖如果有n個頂點,則應該有n-1條邊。此時連通無向圖沒有迴路,就是一顆樹,所以稱為最小生成樹。 最小生成樹是讓邊的總長度之和最短,其中一種方法是可以選擇最短的邊,然後依次
【數據結構】 最小生成樹(二)——kruskal算法
適用於 相同 inf prim 什麽 一段 大樹 集合 n-1 上一期說完了什麽是最小生成樹,這一期咱們來介紹求最小生成樹的算法:kruskal算法,適用於稀疏圖,也就是同樣個數的節點,邊越少就越快,到了數據結構與算法這個階段了,做題靠的就是速度快,時間復雜度小。
HDU 1301 &POJ 1215 Jungle Roads【最小生成樹,Prime演算法+Kruskal演算法】
The Head Elder of the tropical island of Lagrishan has a problem. A burst of foreign aid money was spent on extra roads between villages some years ago.
最小生成樹 & 洛谷P3366【模板】最小生成樹 & 洛谷P2820 局域網
圖片 最大 show bool sca 9.png www. pla ++ 嗯... 理解生成樹的概念: 在一幅圖中將所有n個點連接起來的n-1條邊所形成的樹。 最小生成樹: 邊權之和最小的生成樹。 最小瓶頸生成樹: 對於帶權圖,最大權值最小的生成樹。
最小生成樹算法詳解(prim+kruskal)
span 實現 比較 info 開始 += width map end 最小生成樹概念: 一個有 n 個結點的連通圖的生成樹是原圖的極小連通子圖,且包含原圖中的所有 n 個結點,並且有保持圖連通的最少的邊。 最小生成樹可以用kruskal(克魯斯卡爾)算法或prim(普
最小生成樹( Prim & Kruskal ) 模板加詳解
最小生成樹概念: 一個有 n 個結點的連通圖的生成樹是原圖的極小連通子圖,且包含原圖中的所有 n 個結點,並且有保持圖連通的最少的邊。 最小生成樹可以用kruskal(克魯斯卡爾)演算法或prim(普里姆)演算法求出。最小生成樹其實是最小權重生成樹的簡稱。 p
圖的最小生成樹prim演算法詳解
prim演算法是求圖的最小生成樹的一種演算法,它是根據圖中的節點來進行求解,具體思想大概如下: 首先,將圖的所有節點(我們假定總共有n個節點)分成兩個集合,V和U。其中,集合V儲存的是我們已經訪問過的節點,集合U儲存的是我們未曾訪問的節點。prim演算法第一步就是選定第一個節點放入集合
最小生成樹圖文詳解(Prim演算法)
最小生成樹 就像幾個村莊都不相通, 要修路, 怎麼修, 這個花的錢最少, 這種最優選擇就是最小生成樹 設G = (V, E)是無向連通圖(V是結點集, E是邊集),相對於村莊例子,V就是那些村莊的集合,E就是村莊之間路的集合
7-10 公路村村通 (30 分)(最小生成樹)+prim詳解
現有村落間道路的統計資料表中,列出了有可能建設成標準公路的若干條道路的成本,求使每個村落都有公路連通所需要的最低成本。 輸入格式: 輸入資料包括城鎮數目正整數N(≤1000)和候選道路數目M(≤3N);隨後的M行對應M條道路,每行給出3個正整數,分別是該條道路直接連通的兩個城鎮的編號以及該道
prim演算法基礎詳解(無向賦權圖的最小生成樹MST)
帶權圖分為有向和無向,無向圖的最短路徑又叫做最小生成樹,有prime演算法和kruskal演算法 生成樹的概念:聯通圖G的一個子圖如果是一棵包含G的所有頂點的樹,則該子圖稱為G的生成樹 生成樹是聯通圖的極小連通子圖。 所謂極小是指:若在樹中任意增加一條邊,則將出現一個迴路;