(Day3)並查集

wlqtc發表於2024-06-25

並查集

並查集,就是看誰和誰是一夥的,加入到同一棵樹中。

程式碼要點:

//找到一個結點根結點的函式
int fin(int x)
{
    if(rt[x]==x)return x;
    return rt[x]=fin(rt[x]);//快速查詢
}

//把每一個序號的父結點改為自身
for(int i = 0;i < n;i ++)
{
    rt[i] = i;
}

while(k--)
{
    cin>>x>>y;
  	int xx = fin(x);//如果想把兩個結點放在同一個樹中,需要獲取兩個結點的根結點,然後把兩棵樹連在一起
    int yy = fin(y);
    if(xx!=yy)
    {
        rt[yy]=xx;
        num[xx]+=num[yy];
    }

}

例題:(近模板題)

http://poj.org/problem?id=1611

題目大意:有n個人,m個小組,每個人可以加入多個小組。先輸入n和m,之後的m行,先輸入一個數表示小組有幾個人,然後輸入成員的編號。輸出一共有多少人感染。每次預設0號是感染的。小組內頻繁交流

思路:每次把一個小組後面的所有人連到第一個人上,比較省時間,連就完事了。

時隔4年之後再次寫這道題,寫的方法居然比之前的用時少多了。

AC程式碼:

#include<cstdio>
#include<algorithm>
#include<iostream>
using namespace std;
const int N = 3e4+9;
int n,m,k,x,y;
int rt[N];
int num[N];
int fin(int x)
{
    if(rt[x]==x)return x;
    return rt[x]=fin(rt[x]);
}
int main()
{
    while(cin>>n>>m)
    {
        if(n==0&&m==0)break;
        
        for(int i = 0;i < n;i ++)
        {
            rt[i] = i;
            num[i] = 1;//儲存以i為根結點的樹有多少個結點
        }
           
        while(m--)
        {
            cin>>k>>x;
            int xx = fin(x);//第一個只用查一次就好,其它的掛在第一個上面
            k--;
            while(k--)
            {
                cin>>y;
                int yy = fin(y);
                if(xx!=yy)
                {
                    rt[yy]=xx;
                    num[xx]+=num[yy];//繼承yy的結點數
                }
            }
        }
        int zz = fin(0);
        cout<<num[zz]<<endl;
        
    }
    return 0;
}

相關文章