演算法簡述 基礎資料結構 並查集

2021-09-26 03:51:15 字數 4571 閱讀 5387

列題解析

並查集也是用來維護集合的,和前面學習的 set 不同之處在於,並查集能很方便地同時維護很多集 合。如果用 set 來維護會非常的麻煩。並查集的核心思想是記錄每個結點的父親結點是哪個結點。然而可以知道,這樣空間時間複雜度極高,無法通過題目的時限.

void init()  

}

int get(int x)    

return get(fa[x]); // 返回父結點的根結點 }

void merge(int x, int y) 

}

首先,初始化

int fa[1000]; 

int n, m;

我們先把並查集的框架實現好,便於後面直接呼叫。初始化實際上就是把每個點的父親結點賦值為自己。

void init()  

}

我們繼續實現get函式

int get(int x)      

return get(fa[x]);

}

接下裡我們實現 merge 函式,合併兩個結點到乙個集合。

void merge(int x,int y)  

}

初始化要在 輸入之後,這是平時寫程式很容易錯誤的乙個點。

cin >> n >> m;

init();

for (int i = 0; i < m; i++)

最後我們統計幾何的個數。

int cnt = 0; 

for (int i = 1; i <= n; i++)

} cout << cnt << endl;

實現爭取**:

#includeusing namespace std; 

int fa[10000];

int n,m;

void init()

} int get(int x)

return get(fa[x]);

} void merge(int x, int y)

} int main()

int cnt = 0;

for (int i = 1; i <= n; i++)

}

cout << cnt << endl;

return 0;

}

並查集的時間複雜度很高,最壞可以達到o(n),所以,我們更適用於路勁壓縮的並查集,這一回,就來給大家講一講路勁壓縮後的並查集。

路徑壓縮 的思想是,我們只關心每個結點所在集合的根結點,而並不太關心樹的真正的結構是怎麼樣 的。這樣我們在一次查詢的時候,可以直接把查詢路徑上的所有結點的 都賦值成為根結點。實現 這一步只需要在我們之前的查詢函式上面進行很小的改動。

之前我們判斷無向圖的連通性的時候(有向圖的連通性我們會在之後的課程介紹),用的是 dfs 的方 法。而用並查集來判斷無向圖的連通性,只需要把每一條邊連線的兩個點合併到乙個集合就可以了,都 不必存圖,最後如果集合個數為 ,說明整個圖是連通的。

題目描述

如題,現在有乙個並查集,你需要完成合併和查詢操作。

輸入格式

第一行包含兩個整數n、m,表示共有n個元素和m個操作。

接下來m行,每行包含三個整數zi、xi、yi

當zi=1時,將xi與yi所在的集合合併

當zi=2時,輸出xi與yi是否在同一集合內,是的話輸出y;否則話輸出n

輸出格式

如上,對於每乙個zi=2的操作,都有一行輸出,每行包含乙個大寫字母,為y或者n

輸入輸出樣例

輸入 #1複製

4 72 1 2

1 1 2

2 1 2

1 3 4

2 1 4

1 2 3

2 1 4

輸出 #1複製ny

ny說明/提示

時空限制:1000ms,128m

資料規模:

對於30%的資料,n<=10,m<=20;

對於70%的資料,n<=100,m<=1000;

對於100%的資料,n<=10000,m<=200000。

在一些有n個元素的集合應用問題中,我們通常是在開始時讓每個元素構成乙個單元素的集合,然後按一定順序將屬於同一組的元素所在的集合合併,其間要反覆查詢乙個元素在哪個集合中。

#includeusing namespace std;

const int maxn=100000;

int n,m;

int fa[maxn];

void init()

}int get(int x)

int r=get(fa[x]);

return fa[x]=r;

}void cmp(int x,int y)

int main()else if(get(b)==get(c))

}int get(int x)

return get(fa[x]);

}void cmp(int x,int y)

int main()

} for(int i=1;i<=p;i++)

} for(int i=1;i<=p;i++)

return get( father[x] ); }

void merge (string x,string y)

cout<>n;

for(i=0;i>a>>b;

if(father[a]=="")

if(father[b]=="")

merge(a,b);

} return 0;

}

描述

s 城現有兩座監獄,一共關押著 nn 名罪犯,編號分別為 11 ~ nn。他們之間的關係自然也極不和諧。很多罪犯之間甚至積怨已久,如果客觀條件具備則隨時可能爆發衝突。我們用 「怨氣值」(乙個正整數值)來表示某兩名罪犯之間的仇恨程度,怨氣值越大,則這兩名罪犯之間的積怨越多。如果兩名怨氣值為 cc 的罪犯被關押在同一監獄,他們倆之間會發生摩擦,並造成影響力為 cc 的衝突事件。

每年年末,警察局會將本年內監獄中的所有衝突事件按影響力從大到小排成乙個列表,然後上報到 s 城 z 市長那裡。公務繁忙的 z 市長只會去看列表中的第乙個事件的影響力,如果影響很壞,他就會考慮撤換警察局長。

在詳細考察了 nn 名罪犯間的矛盾關係後,警察局長覺得壓力巨大。他準備將罪犯們在兩座監獄內重新分配,以求產生的衝突事件影響力都較小,從而保住自己的烏紗帽。假設只要處於同一監獄內的某兩個罪犯間有仇恨,那麼他們一定會在每年的某個時候發生摩擦。

那麼,應如何分配罪犯,才能使 z 市長看到的那個衝突事件的影響力最小?這個最小值是多少?

輸入輸入第一行為兩個正整數 n(1 \le n \le 20000)n(1≤n≤20000) 和 m(1 \le m \le 100000)m(1≤m≤100000),分別表示罪犯的數目以及存在仇恨的罪犯對數。

接下來的 mm 行每行為三個正整數 a_j,b_j,c_jaj​

,bj​ ,cj​

,表示 a_jaj​

號和 b_jbj​

號罪犯之間存在仇恨,其怨氣值為 c_jcj​

。資料保證 1輸出

輸出共一行,為 z 市長看到的那個衝突事件的影響力。如果本年內監獄中未發生任何衝突事件,請輸出 00。

輸入樣例 1

4 61 4 2534

2 3 3512

1 2 28351

1 3 6618

2 4 1805

3 4 12884

輸出樣例 1

3512

提示

樣例解釋: 罪犯之間的怨氣值如下面左圖所示,右圖所示為罪犯的分配方法,市長看到的衝突事件影響力是 35123512(由 22 號和 33

號罪犯引發)。其他任何分法都不會比這個分法更優。

當然這題還可以用並查集來做。

**

noip2010

#includeusing namespace std;

const int maxn=200010;

int n,m;

int maze[maxn];

struct nodea[maxn];

int cmp(node a,node b)

void init()

}int get(int x)

void merge(int x,int y)

int main()

sort(a+1,a+1+m,cmp);

for(int i=1;i<=m;i++)elseelse}}

return 0;

}

演算法基礎之資料結構 並查集

題目 合併計算 一共有 n 個數,編號是 1 n,最開始每個數各自在乙個集合中。現在要進行 m 個操作,操作共有兩種 m a b,將編號為 a 和 b 的兩個數所在的集合合併,如果兩個數已經在同乙個集合中,則忽略這個操作 q a b,詢問編號為 a 和 b 的兩個數是否在同乙個集合中 輸入格式 第一...

資料結構基礎 並查集(UnionFind)

union p,q 並操作,將元素p,q併入同乙個組內 find p 查操作,返回元素所在組號,通常是乙個private的輔助函式 isconnected p,q 查操作,查詢元素p,q是否在乙個組內 同乙個組內的元素是相互連線的 基本資料表示 quickunion並查集經典的 路徑壓縮 的優化 基...

資料結構和演算法 並查集

朋友圈問題 並查集,顧名思義,主要功能是合併和查詢,主要處理一些集合的合併問題。假設有n個元素,它們分別屬於一些集合,每個元素最多只能屬於乙個集合,每個集合都有乙個 祖先 這些集合就構成乙個並查集。並查集的表示方式很簡單,只需要乙個陣列v 陣列的大小是元素的個數 對每個元素i,v i 表示它的父節點...