並查集(入門講解)

並查集

所謂並查集,類似於找朋友
現在有一羣人(總共n個人),兩兩之間組成了朋友。
而且朋友的朋友也是自己的朋友(比如A和B是朋友,A和C也是朋友,那麼A,B,C他們三個就互爲朋友。)
而由於我們給數據時只會給K個數,代表這K個人是朋友(一般K的值是2)

並查集作用

1.用來看某個人A和另一個人B是不是朋友,
2.用於查看n個人中,組成了幾個朋友圈(兩個朋友圈就代表,這兩組人互不認識)。
3.有時候求N個城市還需要修幾條路才能完完全暢通
4. … …

舉實例說明

杭電oj1232:暢通工程

Problem Description
某省調查城鎮交通狀況,得到現有城鎮道路統計表,表中列出了每條道路直接連通的城鎮。省政府“暢通工程”的目標是使全省任何兩個城鎮間都可以實現交通(但不一定有直接的道路相連,只要互相間接通過道路可達即可)。問最少還需要建設多少條道路?

Input
測試輸入包含若干測試用例。每個測試用例的第1行給出兩個正整數,分別是城鎮數目N ( < 1000 )和道路數目M;隨後的M行對應M條道路,每行給出一對正整數,分別是該條道路直接連通的兩個城鎮的編號。爲簡單起見,城鎮從1到N編號。
注意:兩個城市之間可以有多條道路相通,也就是說
3 3
1 2
1 2
2 1
這種輸入也是合法的
當N爲0時,輸入結束,該用例不被處理。

Output
對每個測試用例,在1行裏輸出最少還需要建設的道路數目。

Sample Input
4 2
1 3
4 3
3 3
1 2
1 3
2 3
5 2
1 2
3 5
999 0
0

Sample Output
1
0
2
998

思路

首先,這道題符合並查集作用3。
想要知道還需要建幾條路,我們只需要知道現在有幾個“朋友圈”即可,比如現在有n個“朋友圈”。那麼我們只需要再修建(n-1)條路就可以了。

===========================================================================================================

並查集代碼

我們拆分一下:
第一部分:求祖先
我們爲每一個人設置一個“祖先”per[i]。
也就是說我們在一個朋友圈選一個祖先A,只要和A是直接或者間接是朋友的我們都把他的祖先定爲A,也就是說per[i]=A,per[j]=A。

int father(int a) //尋找祖先,利用遞歸
{
    if(per[a]==a)
        return a;
    else
    {
        per[a]=father(per[a]);
        return per[a];
    }
}

第二部分:查看是否屬有相同祖先
現在新輸入2個人,他們兩個有關係。我們就要看看他本來在不在一個圈子裏。不在的話就和成一個圈子
如果i和j的祖先相同,即per[i]==per[j]那麼i和j就在一個朋友圈。如果他們不在一個朋友圈,可是現在他們兩個成朋友了所以需要合成一個朋友圈

void join(int x,int y) //合併朋友圈
{
    int root1,root2;
    root1=father(x);
    root2=father(y);
    if(root1!=root2)
        per[root1]=root2;
}

那麼我們來解決一下這道題

#include<bits/stdc++.h>

using namespace std;
int per[1010];
void sta(int n)      //初始化
{
    for(int i=1;i<=n;i++)
        per[i]=i;
}

int father(int a)   //找祖先
{
    if(per[a]==a)
        return a;
    else
    {
        per[a]=father(per[a]);
        return per[a];
    }
}

void join(int x,int y)   //合併朋友圈
{
    int root1,root2;
    root1=father(x);
    root2=father(y);
    if(root1!=root2)
        per[root1]=root2;
}

int main() 
{
	int m,n,a,b;
	while(scanf("%d",&n)&&n)
    {
        sta(n);
        scanf("%d",&m);
        while(m--)
        {
            scanf("%d %d",&a,&b);
            join(a,b);
        }
        int sum=0;
        for(int i=1;i<=n;i++) //祖先是自己一定代表有一個朋友圈
        {
            if(per[i]==i)
                sum++;
        }
        printf("%d\n",sum-1);
    }
	return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章