time limit: 1000ms memory limit: 65536k 有疑問?點這裡^_^
有n個城市,其中有些城市之間可以修建公路,修建不同的公路費用是不同的。現在我們想知道,最少花多少錢修公路可以將所有的城市連在一起,使在任意一城市出發,可以到達其他任意的城市。
輸入包含多組資料,格式如下。
第一行包括兩個整數n m,代表城市個數和可以修建的公路個數。(n<=100)
剩下m行每行3個正整數a b c,代表城市a 和城市b之間可以修建一條公路,代價為c。
每組輸出佔一行,僅輸出最小花費。
3 21 2 1
1 3 1
1 0
20
#include//這裡的n代表節點數,給節點初始化,m代表邊數,需要給邊數排序,
#include#include//kruskal演算法主要用的是並查集
#includeusing namespace std;
int inf=999999;
int fa[110000];
int n,m;
struct node
q[110000];
void make_set()
}int find(int x)
bool cmp(node x,node y)
) 是乙個含有 n 個頂點的連通網,則按照克魯斯卡爾演算法構造最小生成樹
的過程為:先構造乙個只含 n 個頂點,而邊集為空的子圖,若將該子圖中各個頂點看成是各棵樹上的根結點,則它是乙個含有 n 棵樹的乙個森林。之後,從網的邊集 e 中選取一條權值最小的邊,若該條邊的兩個頂點分屬不同的樹,則將其加入子圖,也就是說,將這兩個頂點分別所在的兩棵樹合成一棵樹;反之,若該條邊的兩個頂點已落在同一棵樹上,則不可取,而應該取下一條權值最小的邊再試之。依次類推,直至森林中只有一棵樹,也即子圖中含有 n-1條邊為止。
2.演算法簡單描述
1).記graph中有v個頂點,e個邊
2).新建圖graphnew,graphnew中擁有原圖中相同的e個頂點,但沒有邊
3).將原圖graph中所有e個邊按權值從小到大排序
4).迴圈:從權值最小的邊開始遍歷每條邊 直至圖graph中所有的節點都在同乙個連通分量中
if 這條邊連線的兩個節點於圖graphnew中不在同乙個連通分量中
新增這條邊到圖graphnew中
kruskal演算法的精髓在於:
每次選取一條邊。
該邊同時滿足:1、在當前未選邊中權值最小;2、與已選邊不構成迴路。
直到選取n-1條表是演算法結束。找到mst活判斷不存在mst。
**設計:
1、利用優先順序佇列將權值小的邊放到佇列最前,優先出對,保證了每次選擇的都是權值最小的邊。
2、利用並查集的查詢及結合把同處同一連通分量中的頂點連到同一父節點下。這樣,每次判斷是
否構成迴路,只要判斷父節點是否相同的即可。
圖例描述:
將所有的邊的長度排序,用排序的結果作為我們選擇邊的依據。這裡再次體現了貪心演算法的思想。資源排序,對區域性最優的資源進行選擇,排序完成後,我們率先選擇了邊ad。這樣我們的圖就變成了右圖
下面繼續選擇, bc或者ef儘管現在長度為8的邊是最小的未選擇的邊。但是現在他們已經連通了(對於bc可以通過ce,eb來連線,類似的ef可以通過eb,ba,ad,df來接連)。所以不需要選擇他們。類似的bd也已經連通了(這裡上圖的連通線用紅色表示了)。
最後就剩下eg和fg了。當然我們選擇了eg。最後成功的圖就是右:
3.簡單證明kruskal演算法
對圖的頂點數n做歸納,證明kruskal演算法對任意n階圖適用。
歸納基礎:
n=1,顯然能夠找到最小生成樹。
歸納過程:
假設kruskal演算法對n≤k階圖適用,那麼,在k+1階圖g中,我們把最短邊的兩個端點a和b做乙個合併操作,即把u與v合為乙個點v',把原來接在u和v的邊都接到v'上去,這樣就能夠得到乙個k階圖g'(u,v的合併是k+1少一條邊),g'最小生成樹t'可以用kruskal演算法得到。
我們證明t'+{}是g的最小生成樹。
用反證法,如果t'+{}不是最小生成樹,最小生成樹是t,即w(t)})。顯然t應該包含,否則,可以用加入到t中,形成乙個環,刪除環上原有的任意一條邊,形成一棵更小權值的生成樹。而t-{},是g'的生成樹。所以w(t-{})<=w(t'),也就是w(t)<=w(t')+w()=w(t'+{}),產生了矛盾。於是假設不成立,t'+{}是g的最小生成樹,kruskal演算法對k+1階圖也適用。
由數學歸納法,kruskal演算法得證。
綜述:
kruskal比較適用於稀疏圖,是一種貪心演算法:為使生成樹上邊的權值和最小,則應使生成樹中每一條邊的權值盡可能地小。
具體做法:找出森林中連線任意兩棵樹的所有邊中,具有最小權值的邊,如果將它加入生成樹中不產生迴路,則它就是生成樹中的一條邊。這裡的關鍵就是如何判斷"將它加入生成樹中不產生迴路"。
《演算法導論》提供的一種方法是採用一種"不相交集合資料結構",也就是並查集了。具體的實現看**好了,反正核心內容就是如果某兩個節點屬於同一棵樹(find_set),那麼將它們合併(union)後一定會形成迴路。
編寫程式:對於如下乙個帶權無向圖,給出所有邊以及權值,用kruskal演算法求最小生成樹。
最小生成樹 kruskal(演算法)
最小生成樹 圖中有好多點呀 n個 讓我們找到n 1條邊,來把他們連上吧,但是要讓這n 1條邊的和最小。kruskal演算法 把所有邊由公升序排列,然後從最小的一條邊找起,如果這條邊的兩點不屬於乙個集合 此處運用並查集 那麼就要這條邊,否則,忽略這條邊吧 一直這樣找下去,直到找了n 1條邊為止,此時,...
最小生成樹 Kruskal演算法
1.概覽 kruskal演算法是一種用來尋找最小生成樹的演算法,由joseph kruskal在1956年發表。用來解決同樣問題的還有prim演算法和boruvka演算法等。三種演算法都是貪婪演算法的應用。和boruvka演算法不同的地方是,kruskal演算法在圖中存在相同權值的邊時也有效。2.演...
最小生成樹 kruskal演算法
2016.12.30 演算法思想 先將邊按照權值排序,從權值最小的邊開始列舉,如果當前邊連線的兩個點不屬於同一集合,就將這兩個點連起來 用到的資料結構是並查集 一直到列舉完所有的邊,此時生成的就是最小生成樹 include include include include using namespac...