演算法學習記錄 並查集

2021-10-22 13:47:50 字數 3299 閱讀 2388

上大物學了會並查集,感覺挺簡單的,而且很好玩,繼dfs,bfs和floyd演算法外又學了一種求連通塊的演算法,綜合下來這幾種演算法各有優劣吧.

並查集演算法詳解見此

模板如下:

#include

using

namespace std;

#define maxn 100001

int father[maxn]

,rank_[maxn]

;void

init

(int n)

}int

find_

(int x)

return father[x]

?x:(father[x]

=find_

(father[x]))

;}void

merge_

(int i,

int j)

else

if(rank_[x]

==rank_[y]

&&x!=y) rank_[y]++;

}int

main()

例題1

洛谷p1551 親戚

題目背景

若某個家族人員過於龐大,要判斷兩個是否是親戚,確實還很不容易,現在給出某個親戚關係圖,求任意給出的兩個人是否具有親戚關係。

*題目描述 規定:x和y是親戚,y和z是親戚,那麼x和z也是親戚。如果x,y是親戚,那麼x的親戚都是y的親戚,y的親戚也都是x的親戚。

*輸入格式 第一行:三個整數n,m,p,(n<=5000,m<=5000,p<=5000),分別表示有n個人,m個親戚關係,詢問p對親戚關係。

*以下m行:每行兩個數mi,mj,1<=mi,mj<=n,表示mi和mj具有親戚關係。*

接下來p行:每行兩個數pi,pj,詢問pi和pj是否具有親戚關係。

*輸出格式 p行,每行乙個』yes』或』no』。表示第i個詢問的答案為「具有」或「不具有」親戚關係。

*輸入輸出樣例 輸入 #1

6 5 3

1 21 5

3 45 2

1 31 4

2 35 6

輸出 #1

yesyes

no

這道題非常簡單,只需要簡單的應用即可

**

#include

using

namespace std;

#define maxn 50010

int father[maxn]

,rank_[maxn]

;void

init

(int n)

}int

find_

(int x)

return x==father[x]

?x:(father[x]

=find_

(father[x]))

;}void

merge_

(int i,

int j)

else

if(rank_[x]

==rank_[y]

&&x!=y) rank_[y]++;

}int

main()

for(

int i=

0;i)return0;

}

例題2

洛谷p1551 親戚

題目背景

若某個家族人員過於龐大,要判斷兩個是否是親戚,確實還很不容易,現在給出某個親戚關係圖,求任意給出的兩個人是否具有親戚關係。

*題目描述 規定:x和y是親戚,y和z是親戚,那麼x和z也是親戚。如果x,y是親戚,那麼x的親戚都是y的親戚,y的親戚也都是x的親戚。

*輸入格式 第一行:三個整數n,m,p,(n<=5000,m<=5000,p<=5000),分別表示有n個人,m個親戚關係,詢問p對親戚關係。

*以下m行:每行兩個數mi,mj,1<=mi,mj<=n,表示mi和mj具有親戚關係。

*接下來p行:每行兩個數pi,pj,詢問pi和pj是否具有親戚關係。

*輸出格式 p行,每行乙個』yes』或』no』。表示第i個詢問的答案為「具有」或「不具有」親戚關係。

*輸入輸出樣例 輸入 #1

6 5 3

1 21 5

3 45 2

1 31 4

2 35 6

輸出 #1

yesyes

no**

#include

using

namespace std;

#define maxn 1010

int t;

int father[maxn]

,rank_[maxn]

;int n,h,r,x[maxn]

,y[maxn]

,z[maxn]

,sp[maxn]

;void

init

(int n)

memset

(x,0

,sizeof

(x))

;memset

(y,0

,sizeof

(y))

;memset

(z,0

,sizeof

(z))

;memset

(sp,0,

sizeof

(sp));

}int

find_

(int x)

void

merge_

(int i,

int j)

else

if(rank_[x]

==rank_[y]

&&x!=y) rank_[y]++;

}boolis(

int i,

int j)

intmain()

}for

(int i=

0;i)merge_

(i,j);}

}}for(

int i=

0;i} cout<<

"no"

memset

(sp,0,

sizeof

(sp));

}return0;

}

這題稍微複雜一點,但是用了並查集還是非常簡單

本來想法,昨天剛搭建完主題,結果今天就說要整改…

18到25號整改一周,這一周先發csdn吧…

演算法學習 並查集

大家肯定有聽說過社交網路裡面的六人理論吧,說是可以通過六個人的聯絡認識世界上的任意乙個人。比如我想認識一下機械系的系花,我先找到機械系的朋友,然後通過朋友介紹認識。這樣可以發現我們的社交圈子其實是有部分重疊的。當然也有可能是我的圈子太小,根本沒有什麼朋友認識那個圈子裡面的人,也有很大可能是機械系花4...

演算法學習之並查集

並查集是一種樹型的結構,常常用來處理一些不相交的集合的合併和查詢問題。查詢 確定元素所在的集合。合併 將兩個集合合併成乙個集合。查詢v所在集合的根節點 int find int v 合併 void merge int x,int y 優化1 int find int x k x while k r ...

演算法學習之 並查集

並查集用於解決連線類問題,判斷網路中節點間的連線狀態。與路徑類問題相比,並查集只回答了節點之間是否連通,而具體的連通路徑並不能確定,因此並查集在某些場景下非常高效。如前所述,此處的並查集實現只提供兩個介面 是否連線,元素合併。下面 使用乙個陣列來記錄每個元素所對應的類別,如果兩個元素的類別相同,則稱...