圖論演算法----並查集中的啟發式合併
一、啟發式合併的演算法原理
一聽這名字,感覺好高大上,實際上很簡單。
由於路徑壓縮在有些題目會損失海量的資訊,用暴力並查集又要超時,所以就出現了啟發式合併演算法。
之前講過並查集的大部分時間都浪費在了find()函式上,於是就對find()函式進行了優化,其實啟發式合併演算法可以使find()函式的時間複雜度控制在O(logn)左右。
並查集是一種樹型的資料結構,而樹也有它的深度,如果我們把一棵深度大的樹的根節點接在了一棵深度小的樹上,那麼整棵樹的深度為那一棵深度大的樹的深度+1,如果我們把一棵深度小的樹的根節點接在了一棵深度大的樹上,則整棵樹的深度為max(深度小的樹的深度+1,深度大的樹的深度)。這就是啟發式合併的原理。
如果感覺很難理解,看下面的圖就知道了。
1、有兩棵樹,一棵高度為3,一棵高度為5。
2、如果是普通的合併,就會造成高度為6的樹。
3、如果是啟發式合併,最後的樹的的高度為5。
好了,啟發式合併的原理講得差不多了,可以發程式碼了,記住height[]陣列初始化為1。
二、啟發式合併的程式碼
配套一個find()函式:void qfsunion(int x,int y) { int a=find(x); int b=find(y); if(height[a]>height[b]) fa[b]=a; else if(height[a]<height[b]) fa[a]=b; else{ fa[a]=b; height[b]++; } }
int find(x)
{
while(fa[x]!=0)
x=fa[x];
return x;
}
三、啟發式合併與路徑壓縮之間的問題
這時有人會問了:為什麼find()函式不用路徑壓縮呢?原因很簡單,因為有了路徑壓縮,啟發式合併演算法就沒有保護資料的效果了。
可以看出,啟發式合併+路徑壓縮並不是最好的選擇,而且路徑壓縮在主動改變樹的高度,但是height陣列的值不能同步改變,有可能會讓啟發式合併出錯。
相關推薦
圖論演算法----並查集中的啟發式合併
一、啟發式合併的演算法原理 一聽這名字,感覺好高大上,實際上很簡單。 由於路徑壓縮在有些題目會損失海量的資訊,用暴力並查集又要超時,所以就出現了啟發式合併演算法。 之前講過並查集的大部分時間都浪費在了
圖論演算法----並查集中的路徑壓縮
一、演算法知識 並查集是一種樹型的高階資料結構,用於處理集合的合併和查詢的問題,應用十分廣泛。 因為主要用合併和查詢,所以叫做並查集。但是要注意,這裡的集合是不能相交的。 並查集主要有兩個函式:find(a)和union(a,b)。 find(a)主要用於查詢a所在樹的根節
圖及演算法----並查集父親查詢寫法比較 DisjointSet
1. 花式查詢並查集 class DisjointSet: def __init__(self, n): # Args: #
簡要題解-圖論-搜尋-並查集-dp-樹形-拓撲-tarjan等等
attentions:對我而言非常好的一道題!最長路! 有幾個點 1、這道題轉化成最長路來求解,方法和最短路類似 2、但這道題是點有正權且只有負權邊,且路徑為單向!那麼精妙之處在於,可以將點權轉化為邊權!!! 3、由於題目中可能出現正環(和最短路相反
並查集中的合併、刪除操作
思路:在一般的並查集操作中設立虛父親節點,當刪除x的時候,不是真的刪除x,而是通過一個對映,即令tmp[x] = cnt, parent[cnt] = cnt;這樣x就從原來的集合中獨立出來了,而我們每次合併x,y的時候,只需合併tmp[x], tmp[y]就可以了。
P1892-團伙【圖論,並查集】
正題 大意 兩個人如果認識就只有兩種關係,敵人或朋友 而: 朋友的朋友是朋友 敵人的敵人是朋友 (敵人之間也可能是敵人) 求團伙總數 解題思路 就像做食物鏈一樣,如
並查集中的啟發式合併
演算法原理 並查集一般有兩種方法來保持複雜度不退化,一種是路徑壓縮,另一種則是按照秩來做啟發式合併。 一般情況下我們都是用第一種,壓縮路徑通過遞推找到祖先節點後,在回溯時將它的子孫節點都直接指向祖先,這樣以後每次呼叫Find( )函式找父親時複雜度就變成了O(1)。但是路
Agri-Net的Kruskal演算法+並查集實現(按大小合併+路徑壓縮)
Agri-Net的Kruskal演算法+並查集實現 演算法複雜度分析 對所有的邊進行排序,排序複雜度為O(mlogm),隨後對邊進行合併,合併使用並查集,並查集使用link by size的方式實現,同時在find函式實現了路徑壓縮。每
演算法-並查集-加邊無向圖
題目描述:給你一個 n 個點,m 條邊的無向圖,求至少要在這個的基礎上加多少條無向邊使得任意兩個點可達~ 輸入描述:第一行兩個正整數 n 和 m 。 接下來的m行中,每行兩個正整數 i 、 j ,表示點i與點j之間有一條無向道路。輸出描述:輸出一個整數,表示答案例 :輸入4
簡單合併並查集中的子集樹
//此程式碼是資料結構的原始模板,可以剛接觸或考研時借鑑下,不適於刷題 #include<stdio.h> #include<malloc.h> #define ERROR 0
NOIP複賽複習(十三)圖論演算法鞏固與提高
一、圖的儲存 1、鄰接矩陣 假設有n個節點,建立一個n×n的矩陣,第i號節點能到達第j號節點就將[i][j]標記為1(有權值標記為權值), 樣例如下圖: /*無向圖,無權值*/ i
資料結構和演算法:第八章 圖論演算法
9.1 若干定義 圖的定義:一個圖(Graph) G=(V,E)是由頂點的集合V和邊Edge的集合E組成的。每一條邊就是一個頂點對(v,w),其中(v,w) ∈E。有時候也把邊叫做弧。如果頂點對是有序的,那麼圖就是有向的。有的圖也叫做有向圖。頂點w和頂點v鄰接當且僅當(v,w)
圖論演算法模板
Under the bridge downtown Forgot about my love Under the bridge downtown I gave my life away Luogu P4779【模板】單源最短路徑(標準版) //時間複雜度O((n+m)log
PAT 備考第一天——圖論演算法(一)
大綱: 必考考點: 1.圖的定義和相關術語 2.圖的儲存(鄰接矩陣和鄰接表) 3.圖的遍歷(DFS和BFD) 4.最短路徑演算法 5.拓撲排序 非重點考點: 1.關鍵路徑 2.最短路徑中的Bellman-Ford和SPFA 甲級考綱以外的考點: 最小生成樹演算法 一、圖的
第9章 圖論演算法
圖的表示方法 鄰接矩陣 : adjacent matrix是一個二位陣列,對於每條邊(u,v),置A[u][v]等於true;否則,陣列的元素就是false。如果邊有一個權,那麼可以置A[u][v]等於該權,而使用一個很大或者很小的權作為標記表示不存在的邊。適用於稠密的圖
牛客練習賽32 D Tarjan無向圖求橋+並查集維護
題目描述: 小p和他的朋友約定好去遊樂場遊玩,但是他們到了遊樂場後卻互相找不到對方了。 遊樂場可以看做是一張n個點,m條道路的圖,每條道路有邊權wi,表示第一次經過該道路時的花費(第二次及以後經過時花費為0)。 現在,小p要去找他的朋友,但他的朋友行蹤很詭異,小p總是要遍歷完這n個點才能找到他,
圖論演算法講解--最短路--Dijkstra演算法
一.緒論 要學習最短路演算法我們首先應該知道什麼是圖以及什麼是最短路。 圖在離散數學中的定義為:圖G=(V,E)是一個二元組(V,E)使得E⊆[V]的平方,所以E的元素是V的2-元子集。為了避免符號上的混淆,我們總是預設V∩B=Ø。集合V中的元素稱為圖G的定
[C++一本通-圖論演算法] 例4-4 最小花費
題目描述 在n個人中,某些人的銀行賬號之間可以互相轉賬。這些人之間轉賬的手續費各不相同。給定這些人之間轉賬時需要從轉賬金額里扣除百分之幾的手續費,請問A最少需要多少錢使得轉賬後B收到100元。 輸入輸出格式 輸入格式: 第一行輸入兩個正整數n,m,分別表示總人數和可以互相轉賬的人的對數。 以下m行每行輸入三個
模板庫(三) - 圖論演算法模板
寫在前面 “模板庫”這一系列文章用來複習 O I OI
圖論演算法進階習題集
最近在做一些圖論的題,像steiner 樹一類的演算法,還有網路流,下面轉載了500道進階練習題,希望以後能針對性的訓練一下,畢竟是熟能生巧,不練不知道。 =============================以下是最小生成樹+並查集============