並查集
並查集,就是看誰和誰是一夥的,加入到同一棵樹中。
程式碼要點:
//找到一個結點根結點的函式
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;
}