暢通工程(並查集)
【題目】某省調查城鎮交通狀況,得到現有城鎮道路統計表,表中列出了每條道路直接連通的城鎮。省政府“暢通工程”的目標是使全省任何兩個城鎮間都可以實現交通(但不一定有直接的道路相連,只要互相間接通過道路可達即可)。問最少還需要建設多少條道路?
【解答】並查集基本演算法。定義陣列parent,每個城市可以用陣列下標指示,parent[index]的值代表與index聯通的城市。
程式碼:
int[] parent = new int[5];
public int findRoot(int x)
{
int r = x;
//根節點性質root == parent[root]
while (r != parent[r])
r = parent[r];
return r;
}
public void Merge(int x, int y)
{
int p , q;
p = findRoot(x);
q = findRoot(y);
if (p != q) { //隨便指定
parent[x] = q;
}
}
以上程式碼現實了基本功能,我們可以做一些優化。需要優化的是這個演算法中使用頻率最高的方法,即對根節點的查詢的方法(findRoot)。
1.將高度小的樹合併到高度大的樹
上面程式碼中兩顆樹是隨意合併的,為了是查詢速率更高,就要使整個樹儘量保持平衡。假設兩顆樹的高度是h1,h2,則合併後的高度h是:
- if(h1 != h2) h = max(h1, h2)
- if(h1 == h2) h = h1+1
2.路徑壓縮
查詢根節點(r = parent[r]),修改查詢路徑上的所有節點,將他們都指向根節點。
優化後的程式碼:
int[] parent = new int[5]; //值與下標一致,初始值就是父節點就是自身
int[] height = new int[5]; //記錄樹的高度
public int findRoot(int x)
{
int r = x;
while (r != parent[r])
r = parent[r];
int i = x, j;
//壓縮路徑
while (i != r)
{
j = parent[i];
parent[i] = r;
i = j;
}
return r;
}
public void Merge(int x, int y)
{
int p , q;
p = findRoot(x);
q = findRoot(y);
if (p != q) {
//使高度小的樹合併到高度大的樹
if (height[p] == height[q])
{
parent[p] = q;
height[q]++;
}else if (height[p] > height[q]){
parent[q] = p;
}else {
parent[p] = q;
}
}
}
關於並查集的詳細介紹,請參看這篇文章:http://blog.csdn.net/dm_vincent/article/details/7655764
相關文章
- 資料結構:速通並查集資料結構並查集
- 並查集到帶權並查集並查集
- hdu 1232通暢工程
- 【並查集】【帶偏移的並查集】食物鏈並查集
- 並查集(一)並查集的幾種實現並查集
- 3.1並查集並查集
- 並查集(小白)並查集
- 並查集(Union Find)並查集
- 並查集應用並查集
- The Door Problem 並查集並查集
- 並查集練習並查集
- 並查集的使用並查集
- 並查集—應用並查集
- 寫模板, 並查集。並查集
- 並查集跳躍並查集
- 各種並查集並查集
- 食物鏈(並查集)並查集
- 並查集(二)並查集的演算法應用案例上並查集演算法
- The Suspects-並查集(4)並查集
- [leetcode] 並查集(Ⅰ)LeetCode並查集
- [leetcode] 並查集(Ⅱ)LeetCode並查集
- [leetcode] 並查集(Ⅲ)LeetCode並查集
- 並查集演算法並查集演算法
- 並查集深度應用並查集
- 【轉】種類並查集並查集
- 並查集java實現並查集Java
- 並查集-Java實現並查集Java
- 並查集題目合集並查集
- 並查集以及應用並查集
- 並查集的應用並查集
- (Day3)並查集並查集
- 並查集擴充套件並查集套件
- 簡單易懂的並查集演算法以及並查集實戰演練並查集演算法
- Linux檢查遠端埠是否通暢Linux
- 關於並查集問題並查集
- 並查集的應用2並查集
- 並查集の進階用法並查集
- 並查集(UnionFind)技巧總結並查集