并查集,《算法》1.5节。通常可以用来判断一个图有几个联通块,或是需要建几条路才能将联通块连在一起。
C++版
//
// main.cpp
// uf
//
// Created by 王博文 on 15/3/25.
// Copyright (c) 2015年 Bowen. All rights reserved.
//
#include <iostream>
using namespace std;
int parts=11;
int pre[11];
int find(int x){
int r=x;
while(pre[r]!=r){
r=pre[r];
}
return r;
}
void join(int x, int y){
int fx=find(x);
int fy=find(y);
if(fx==fy) return;
pre[fx]=pre[fy];
parts--;
}
int main(){
int uf[11][2]={4, 3, 6, 9, 2, 8, 5, 7, 6, 1, 6,
3, 8, 5, 4, 1, 9, 0, 2, 1, 0, 7};
for(int i=0; i<11; i++){
pre[i]=i;
}
for(int i=0; i<11; i++){
int x = uf[i][0];
int y = uf[i][1];
cout<<x<<"'s parent is "<<y<<endl;
join(x,y);
}
cout<<"After union "<<endl;
for(int i=0; i<11; i++){
cout<<i<<"'s parent is "<<pre[i]<<endl;
}
cout<<"The set has "<<parts<<" components"<<endl;
}
Java版
import java.util.Scanner;
// 并查集 判断一个图中有几个联通块
public class UnionFind {
private int[] father;//
private int count;// 分量数量
public UnionFind(int N){
count=N;
father=new int[N];
for(int i=0;i<N;i++){
father[i]=i;
}
}
public int count() { return count; }
public boolean connected(int p,int q){
return father[p]==father[q];
}
public int find(int p){
/*if(p!=father[p]){
father[p]=find(father[p]);
}
return father[p];*/
while(p!=father[p]){
p=father[p];
}
return p;
}
public void union(int p,int q){
int proot=find(p);
int qroot=find(q);
if(proot==qroot) return;
father[proot]=qroot;// 直接将p挂载到q
count--;
}
public static void main(String[] args) {
Scanner cin=new Scanner(System.in);
int N=cin.nextInt();
UnionFind uf=new UnionFind(N);
System.out.println(N+" nodes");
int M=cin.nextInt();
while(M-->0){
int p=cin.nextInt();
int q=cin.nextInt();
// 若p q 已经在同一块中,则不需要采取任何行动
if(uf.connected(p,q)) continue;
uf.union(p,q);
System.out.println(p+" "+q);
}
System.out.println(uf.count()+" components");
}
}