並查集以及應用
參考
http://blog.csdn.net/dm_vincent/article/details/7655764
動態連通圖可能的操作
查詢節點屬於的組:陣列對應位置的值即為組號
判斷兩個節點是否屬於同一組:分別得到兩個節點的組號,然後判斷組號是否相等
連線兩個節點:分別得到兩個節點的組號,組號相同時,退出操作,組號不同時,通過判斷組大小程式連線
獲取組的數目:初始化為整個陣列的大小,每次連線後,遞減一
class UF;
Union(int i,int j); 連線
int Find(int i); 查詢組號
BOOL Cnnected(int i,int j) 判斷是否為同一組
int Count(); 返回組號
class UF
{
private :
int* id;
int count;
public:
int* sz;
UF(int N)
{
count = N;
id = new int[N];
sz = new int[N];
for (int i = 0; i < N; i++)
{
id[i] = i;
sz[i] = 1;
}
}
int Find(int i) //路徑壓縮
{
while (i != id[i])
{
id[i] = id[id[i]]; //將父節點設定為爺爺節點
i = id[i];
}
return i;
}
int Count()
{
return count;
}
BOOL Connected(int i, int j)
{
return Find(i) == Find(j);
}
VOID Union(int i, int j)
{
int a;
int b;
a = Find(i);
b = Find(j);
if (Find(i) == Find(j))
{
return;
}
if (sz[i] < sz[j]) //比重
{
id[a] = b;
}
else
{
id[b] = a;
}
count--;
}
};
int main()
{
UF uf(10);
int i;
int j;
int V1[6][2] = { 1,2,4,5,7,6,3,9,7,2,3,2 };
for (i = 0; i < 6; i++)
{
uf.Union(V1[i][0], V1[i][1]);
}
j = uf.Count();
printf("組號 %d", j);
return 0;
}
-----------------------------------------------------------------------------------------------
poj上一個題目 個人解題的思路 也有借鑑
A吃B B吃C C吃A 總共樹林裡有三種動物,N個動物 現在有一定數量的話
要求判斷真假 並輸出假話個數
解題思路:
不同於普通的並查集,這個題目節點直接存在一定的利害關係,故考慮這是一個帶權並查集,即確定每個節點所帶的數值來表示其與父節點或子節點的關係。
一,確定權值(這裡應該是相對於子節點)
現在定義如下
取 0 1 2 來表示關係,原因:第一 父節點和子節點關係有三種——同類 相對於子節點(被父節點吃 和吃父節點)
相對於父節點(吃子節點和被子節點吃) 第二 題意所需
在後續會明白
0 表示父節點和子節點同類
1 表示子節點被父節點吃或父節點吃子節點
2 表示子節點吃父節點或父節點被子節點吃
二,初始化
對每個節點進行初始化
節點結構
struct animal{
int relation;
int parents;}
在初始化時每個節點按序賦值 ,relation為1(自己與自己是同類),parents=id(自己)
壓縮路徑
在每一次查詢的過程中,將子節點連線到爺爺節點上
animal[i].parents = animal[animal[i].parents].parents;
這裡就出現了這個問題的核心 在壓縮路徑後,由於破壞了原有的狀態,如何根據原有的資訊,來得到新的資訊。
即如何確定子節點和爺爺節點的relation
這裡採用列舉法觀察
子節點
父節點
子節點和爺爺節點的關係
0
0
0
0
1
1
0
2
2
1
0
1
1
1
2
1
2
3
2
0
2
2
1
0
2
2
1
不難發現 這裡子節點和爺爺節點的關係可寫為
r[子爺] = (r[子] + r[父])%3
現在處理稍複雜情況連線
x->y->p x->q
現在將兩個進行合併 即將兩個根節點相連
這裡處理方法為
1. 通過x->q推出 q相對於x的關係
這裡通過列舉
子節點
父相對於子
0
0
1
2
2
1
規律為 r[父相對於子] = (3- r[子])%3
現在過程為
2.x->y->p 在通過x找根節點時 將x連線到p上
這裡 r[x1] = (r[x]+r[y])%3
對於x->q
r[q相對於x] = (3-r[x])%3
現在等價為q->x->p
將q連線到p上
r[q] =(r[x1] + r[q])
= (r[x] + r[y] + (3-r[x])%3 )%3
Union函式
最為複雜 這裡情況多變但由於存在路徑壓縮 所以知樹的高度一般最多不會超過三層。故最長只會出現
x1->x2->x3 與y1->y2->y3 進行連線
這應該是最複雜的情況
首先在處理時確定一個前提 那就是 只有從y到x的連線
就是每句話的後一個向前一個進行連線
現在是最簡單的
situaion 1:
1 x1 y1 (x1 and y1 are all the roots at this
situation)
solution:
Find(x1)
change relaion(x1)
Find(y1)
change relaion(y1) //nothing happen
y1.parent = x1
y1.relation = 1-1
situation 2:
2 x1 y1 (x1 and y1 are all
the roots at this situation)
solution:
Find(x1)
change relaion(x1)
Find(y1)
change relaion(y1) //nothing happen
y1.parent = x1
y1.relation = 2-1
situation 3:
1 x2 y1(x2->x1 y1 is the root)
solution:
Find(x2) //xroot = x1
change relaion(x2)
Find(y1)
change relaion(y1)
y1.parent = x2
y1.relation = 1-1
situation 4:
2 x2 y1((x2->x1 y1 is the root)
solution:
Find(x2) //xroot = x1
change relaion(x2)
Find(y1)
change relaion(y1)
yroot.parent = x2
yroot.relation = 2-1
situation 5:
1 x2 y2((x2->x1 y2->y1 )
solution:
Find(x2) //xroot = x1
change relaion(x2)
Find(y2) //yroot = y1
change relaion(y2)
yroot.parent = xroot
yroot.relation = ((3-r[yroot])%3 + d - 1(話中的數) +
r[x2])%3
而對於更加複雜的情況 可用上述式子進行等效替換 故不進行贅述。
這裡是大致思想
程式碼就不進行貼上
相關文章
- 並查集應用並查集
- 並查集—應用並查集
- 並查集深度應用並查集
- 並查集的應用並查集
- 並查集的應用2並查集
- 並查集應用總結並查集
- 並查集(二)並查集的演算法應用案例上並查集演算法
- 並查集詳解與應用並查集
- 並查集的簡單應用並查集
- 並查集的分析及應用並查集
- 並查集擴充套件應用並查集套件
- 並查集演算法Union-Find的思想、實現以及應用並查集演算法
- 並查集經典應用場景並查集
- 並查集的應用:hdu 1213並查集
- 社交網路 (並查集的應用)並查集
- 【學習筆記】並查集應用筆記並查集
- 並查集(Union-Find) 應用舉例並查集
- 【帶權並查集】理論和應用並查集
- 食物鏈(並查集的簡單應用)並查集
- 並查集 (Union-Find Sets)及其應用並查集
- 簡單易懂的並查集演算法以及並查集實戰演練並查集演算法
- 並查集的初級應用及進階並查集
- 並查集在實際問題中的應用並查集
- 資料結構 — 並查集的原理與應用資料結構並查集
- 並查集到帶權並查集並查集
- 並查集(Union-Find) 應用舉例 --- 基礎篇並查集
- 【並查集】【帶偏移的並查集】食物鏈並查集
- 並查集(一)並查集的幾種實現並查集
- 【演算法】並查集的運用演算法並查集
- 3.1並查集並查集
- 並查集(小白)並查集
- 資料結構之Kruskal演算法(並查集的應用)資料結構演算法並查集
- 並查集(Union Find)並查集
- The Door Problem 並查集並查集
- 並查集練習並查集
- 並查集的使用並查集
- 寫模板, 並查集。並查集
- 並查集跳躍並查集