並查集 和 路徑壓縮

      並查集,在一些有N個元素的集合應用問題中,我們通常是在開始時讓每個元素構成一個單元素的集合,然後按一定順序將屬於同一組的元素所在的集合合併,其特點是看似並不複雜,但數據量極大並查集是一種樹型的數據結構,用於處理一些不相交集合的合併及查詢問題。常常在使用中以森林來表示。

      並查集通常包含兩個常用的函數 : find() join() ,find()函數是用來查看某個體祖先的,join()函數是將兩個 個體的祖先聯繫在一起。這裏再提一下路徑壓縮,因爲我們在看兩個體是否具有某種關係時只需查看他們是否有共同的祖先即可,所以我們在join()函數中,在查找某個體的祖先時將其路徑上的所有個體均直接指向其祖先,那麼在查找時會方便很多。

看例題(HDUOJ-1856-More is better):

問題描述:

      說 Mr Wang 需要學生來幫他完成一個工程,學生的個數越多越好,當然選擇學生是有前提的,那就是選擇的學生必須間接或直接爲朋友關係,這時他找了間足夠大的房子裏面有1000 000 個學生,經過他的挑選未被選擇的學生將離開房子,請你幫他選擇出最多能選擇多少學生(至少爲一個)。

輸入:第一行爲關係是直接朋友的學生對數 n  ( 0 =< n <= 10 0000),然後包含n行每行爲一對學生A,B(1<=A,B<=1000 000);

輸出:輸出最多能選取的學生個數。

代碼奉上:

#include<stdio.h>
#include<string.h>
int pre[1000000]; //並查集用來儲存學生間的朋友關係(即具有共同祖先的個體爲朋友關係)
int sum[1000000]; //記錄每個個體有多少個朋友
int max = 0; //記錄個體擁有朋友最多的數量
int find(int x){  //查找祖先的函數
	if (pre[x]==x)
	return x;
	pre[x] = find(pre[x]);//這裏爲路徑壓縮,將每一個個體的父親直接設爲祖先
	return pre[x];
}
void join(int x,int y){//鏈接函數,將兩個體的祖先聯繫起來
	int fx = find(x);
	int fy = find(y);
	if (fx==fy)
	return ;
	pre[fx] = fy;
	sum[fy] += sum[fx]; //將個體擁有朋友的數量合併
	max = max<sum[fy]?sum[fy]:max; //尋找最大值
	
}
int main (){
	int n,a,b,i;
	while (scanf("%d",&n) != EOF){
	for (i=0;i<=2*n;i++){//初始化,一開設定,每個學生都沒有朋友,即sum = 1;
		pre[i] = i;
		sum[i] = 1;
	}
	
	for (i=0;i<n;i++){
		scanf("%d%d",&a,&b);
		join(a,b);//將具有朋友關係的學生合併
	}
	printf("%d\n",max);
	max = 1;   初始化max進行下一輪數據的測試
	}
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章