做練習 宗教信仰(並查集)

2021-10-07 01:43:10 字數 1578 閱讀 5413

世界上有許多宗教,你感興趣的是你學校裡的同學信仰多少種宗教。

你的學校有n名學生(0 < n <= 50000),你不太可能詢問每個人的宗教信仰,因為他們不太願意透露。但是當你同時找到2名學生,他們卻願意告訴你他們是否信仰同一宗教,你可以通過很多這樣的詢問估算學校裡的宗教數目的上限。你可以認為每名學生只會信仰最多一種宗教。

輸入包括多組資料。

每組資料的第一行包括n和m,0 <= m <= n(n-1)/2,其後m行每行包括兩個數字i和j,表示學生i和學生j信仰同一宗教,學生被標號為1至n。輸入以一行 n = m = 0 作為結束。

對於每組資料,先輸出它的編號(從1開始),接著輸出學生信仰的不同宗教的數目上限。

10 9

1 21 3

1 41 5

1 61 7

1 81 9

1 10

10 4

2 34 5

4 85 8

0 0case 1: 1

case 2: 7

「信仰同一宗教」這一關係是乙個等價關係(自反、傳遞、對稱),因此,很容易想到,最大的信仰數量是這一等價關係所匯出的等價類的數量。

看到這裡,立刻明白這道題是非常原始的並查集問題。

並查集是一種高效的記錄、查詢等價類的方式,它把屬於同乙個等價類的集合通過前驅記錄的形式構成一棵樹,並用根節點來代表整個等價類。

並查集支援find(查詢)、merge(合併)兩種基本的操作。

在並查集中,路徑壓縮是一項非常巧妙的設計,我們在find的同時,將迭代(或遞迴)查詢路徑上的節點都改為直接掛在根之下,這樣,不僅不影響的查詢的正確性,又縮減樹的深度,使得後續的find操作的代價趨近於乙個常數。

我會在**實現中,實現乙個基本的並查集模板。

#include

#pragma warning(disable: 4996)

class

mergefindset

~mergefindset()

intsize()

// 尋找i的祖宗,它代表i所屬的等價類

intfind

(int i)

// 合併i和j所屬的等價類

void

merge

(int i,

int j)

// 詢問i和j是否屬於同一等價類

bool

check

(int i,

int j)

// 計數有多少個等價類

intcount()

};intmain()

printf

("case %d: %d\n"

, icase, mfset-

>

count()

);delete mfset;

}return0;

}

並查集有很多變化,並不是所有都像這道題這麼簡單。

首先,有些題需要精巧地找到恰當地等價關係,一旦等價關係找錯,就等著wa吧。而有些並查集的題不僅需要維護乙個parents(前驅陣列),還需要維護一些額外的資訊,這些維護操作在find和merge過程中都可能發生。

宗教信仰(並查集)

問題描述 現如今世界上有如此多的宗教信仰,要將它們所有的都保持聯絡是非常困難的。你對於找出在乙個大學裡面同學們有多少不同的宗教信仰感興趣。你知道這個大學裡面有n個學生。如果讓你去乙個乙個問每乙個學生的宗教信仰是不可能的。而且,許多學生不願意表露他們的宗教信仰。有個方法可以避免這個問題,就是去問m 0...

並查集 宗教信仰

時間限制 1 sec 記憶體限制 128 mb 提交 15 解決 8 提交 狀態 討論版 世界上有許多不同的宗教,現在有乙個你感興趣的問題 找出多少不同的宗教,在你的大學中的大學生信仰了多少種不同的宗教。你知道在你的大學有n個學生 0輸入包含多組測試資料。每組測試資料的開頭包含兩個整數n和m。接下來...

宗教信仰(並查集)

問題描述 現如今世界上有如此多的宗教信仰,要將它們所有的都保持聯絡是非常困難的。你對於找出在乙個大學裡面同學們有多少不同的宗教信仰感興趣。你知道這個大學裡面有n個學生。如果讓你去乙個乙個問每乙個學生的宗教信仰是不可能的。而且,許多學生不願意表露他們的宗教信仰。有個方法可以避免這個問題,就是去問m 0...