並查集模板:
快速查找 並查集
這是一個eager的並查集,就是在合併兩個節點的時候將這兩個節點的組份id修改成同一個根節點的編號.
public class QuickFindUF {
private int[] componentID; //各個節點(數組索引)所屬的組份(數組值)
private int count; // number of components
public QuickFindUF(int n)
{
if(n<0) throw new IllegalArgumentException();
this.count=n;
this.componentID=new int[n];
for(int i=0;i<n;i++)
{
componentID[i]=i;
}
}
//連接兩個節點 O(n)
public void union(int p,int q){
int rootP=this.find(p);
int rootQ=this.find(q);
if(rootP==rootQ)
return;
int label=Math.min(rootP, rootQ);
int max=Math.max(rootP, rootQ);
for(int i=0;i<this.componentID.length;i++)
if(this.componentID[i]==max)
this.componentID[i]=label;
count--;
}
//在查找p節點所屬組份ID過程中會將實際上同屬於一個組份的不同ID修改成相同
public int find(int p)
{
int n=this.componentID.length;
if(p<0||p>=n)
throw new IllegalArgumentException("index " + p + " is not between 0 and " + (n-1));
while(p!=this.componentID[p])
{
this.componentID[p]=componentID[componentID[p]];
p=componentID[p];
}
return p;
}
public boolean isConnected(int p,int q)
{
int n=this.componentID.length;
if(p<0 || p>=n || q<0 || q>=n)
throw new IllegalArgumentException("index " + p +" or "+q+ " is not between 0 and " + (n-1));
return this.find(p)==this.find(q);
}
public int count()
{
return this.count;
}
}
快速合併 並查集
public class QuickUnionUF {
private int[] componentID;
private int count; // number of components
public QuickUnionUF(int n)
{
if(n<0) throw new IllegalArgumentException();
this.count=n;
this.componentID=new int[n];
for(int i=0;i<n;i++)
{
componentID[i]=i;
}
}
//連接兩個節點
void union(int p,int q) //O(N)
{
int rootP=this.find(p);
int rootQ=this.find(q);
if(rootP==rootQ)
return;
this.componentID[rootP]=rootQ;
count--;
}
//在查找p節點所屬組份ID過程中會將實際上同屬於一個組份的不同ID修改成相同
int find(int p) //O(N)
{
int n=this.componentID.length;
if(p<0||p>=n)
throw new IllegalArgumentException("index " + p + " is not between 0 and " + (n-1));
while(p!=this.componentID[p])
{
this.componentID[p]=componentID[componentID[p]];
p=componentID[p];
}
return p;
}
boolean isConnected(int p,int q) //O(N)
{
int n=this.componentID.length;
if(p<0 || p>=n || q<0 || q>=n)
throw new IllegalArgumentException("index " + p +" or "+q+ " is not between 0 and " + (n-1));
return this.find(p)==this.find(q);
}
int count()
{
return this.count;
}
加權快速合併 並查集
public class WeightedQuickUnionUF {
/*
* 加權快速合併並查集在快速合併並查集基礎上:把 深度較小的樹合併到較大的樹上
*/
int[] componentID;
int[] size; //以下標i爲根節點的節點數
int count; // number of components
public WeightedQuickUnionUF(int n) //O(N)
{
if(n<0) throw new IllegalArgumentException();
this.count=n;
this.componentID=new int[n];
this.size=new int[n]; //以索引i爲根節點的樹的總結點數
for(int i=0;i<n;i++)
{
componentID[i]=i;
this.size[i]=1;
}
}
//連接兩個節點
void union(int p,int q) //O(1)
{
int rootP=this.find(p);
int rootQ=this.find(q);
if(rootP==rootQ)
return;
if(this.size[rootP]<=this.size[rootQ])
{
this.size[rootQ]+=this.size[rootP];
this.componentID[rootP]=rootQ;
}
else
{
this.size[rootP]+=this.size[rootQ];
this.componentID[rootQ]=rootP;
}
count--;
}
//在查找p節點所屬組份ID過程中會將實際上同屬於一個組份的不同ID修改成相同
int find(int p) //O(N),O(the depth of p) if given root nodes
{
int n=this.componentID.length;
if(p<0||p>=n)
throw new IllegalArgumentException("index " + p + " is not between 0 and " + (n-1));
while(p!=this.componentID[p])
{
this.componentID[p]=componentID[componentID[p]];
p=componentID[p];
}
return p;
}
boolean isConnected(int p,int q)
{
int n=this.componentID.length;
if(p<0 || p>=n || q<0 || q>=n)
throw new IllegalArgumentException("index " + p +" or "+q+ " is not between 0 and " + (n-1));
return this.find(p)==this.find(q);
}
int count()
{
return this.count;
}
}
加權路徑壓縮快速合併 並查集
public class WeightedQuickUnionPathCompressionUF {
int[] father;
int[] size;
int count; // number of components
public WeightedQuickUnionPathCompressionUF(int n) //O(N)
{
if(n<0) throw new IllegalArgumentException();
this.count=n;
this.father=new int[n];
this.size=new int[n]; //以索引i爲根節點的樹的總結點數
for(int i=0;i<n;i++)
{
father[i]=i;
this.size[i]=1;
}
}
//連接兩個節點
boolean union(int p,int q) //O(1)
{
int rootP=this.find(p);
int rootQ=this.find(q);
if(rootP==rootQ)
return false;
if(this.size[rootP]<=this.size[rootQ])
{
this.size[rootQ]+=this.size[rootP];
this.father[rootP]=rootQ;
}
else
{
this.size[rootP]+=this.size[rootQ];
this.father[rootQ]=rootP;
}
count--;
return true;
}
//在查找p節點所屬組份ID過程中會將實際上同屬於一個組份的不同ID修改成相同
int find(int p) //O(N),O(the depth of p) if given root nodes
{
int n=this.father.length;
if(p<0||p>=n)
throw new IllegalArgumentException("index " + p + " is not between 0 and " + (n-1));
int root=p;
while(root!=this.father[root])
root=this.father[root];
while(p!=root)
{
int new_root=this.father[p];
this.father[p]=root;
p=new_root;
}
return p;
}
boolean isConnected(int p,int q)
{
int n=this.father.length;
if(p<0 || p>=n || q<0 || q>=n)
throw new IllegalArgumentException("index " + p +" or "+q+ " is not between 0 and " + (n-1));
return this.find(p)==this.find(q);
}
int count()
{
return this.count;
}
class Solution {
public static int maxCount=1010;
public int[] findRedundantConnection(int[][] edges) {
WeightedQuickUnionPathCompressionUF uf=new WeightedQuickUnionPathCompressionUF(maxCount);
for(int[] e:edges){
if(!uf.union(e[0],e[1]))
return e;
}
return new int[]{0,0};
}
}
public class WeightedQuickUnionPathCompressionUF {
int[] father;
int[] size;
int count; // number of components
public WeightedQuickUnionPathCompressionUF(int n) //O(N)
{
if(n<0) throw new IllegalArgumentException();
this.count=n;
this.father=new int[n];
this.size=new int[n]; //以索引i爲根節點的樹的總結點數
for(int i=0;i<n;i++)
{
father[i]=i;
this.size[i]=1;
}
}
//連接兩個節點
boolean union(int p,int q) //O(1)
{
int rootP=this.find(p);
int rootQ=this.find(q);
if(rootP==rootQ)
return false;
if(this.size[rootP]<=this.size[rootQ])
{
this.size[rootQ]+=this.size[rootP];
this.father[rootP]=rootQ;
}
else
{
this.size[rootP]+=this.size[rootQ];
this.father[rootQ]=rootP;
}
count--;
return true;
}
//在查找p節點所屬組份ID過程中會將實際上同屬於一個組份的不同ID修改成相同
int find(int p) //O(N),O(the depth of p) if given root nodes
{
int n=this.father.length;
if(p<0||p>=n)
throw new IllegalArgumentException("index " + p + " is not between 0 and " + (n-1));
int root=p;
while(root!=this.father[root])
root=this.father[root];
while(p!=root)
{
int new_root=this.father[p];
this.father[p]=root;
p=new_root;
}
return p;
}
boolean isConnected(int p,int q)
{
int n=this.father.length;
if(p<0 || p>=n || q<0 || q>=n)
throw new IllegalArgumentException("index " + p +" or "+q+ " is not between 0 and " + (n-1));
return this.find(p)==this.find(q);
}
int count()
{
return this.count;
}
}
[外交]
package ShunFeng;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Scanner;
public class Main1 {
public static void main(String[] args) {
Scanner cin = new Scanner(System.in);
int n = cin.nextInt(); // 參會人數
int m = cin.nextInt(); // 語言數量
int k = cin.nextInt(); // 記錄條數
HashMap<Integer, ArrayList<Integer>> record = new HashMap<>();
for (int i = 0; i < k; i++) {
int a = cin.nextInt(), b = cin.nextInt();
if (record.containsKey(b)) {
record.get(b).add(a);
} else {
ArrayList<Integer> tmp = new ArrayList<>();
tmp.add(a);
record.put(b, tmp);
}
}
QuickUnionUF uf = new QuickUnionUF(n); //建立大小爲n的並查集,不會任何語言的人或者只會一種語言(並且該語言不被其他任何人掌握的)始終獨立爲一個組份
for (int i : record.keySet()) {
ArrayList<Integer> arr = record.get(i);
int a = arr.get(0);
for (int j = 1; j < arr.size(); j++) {
uf.union(a-1, arr.get(j)-1); //人的編號減一對應數組下標的範圍
}
}
System.out.println(uf.count()-1);
/*
7 4 9
1 1
2 1
3 1
4 2
3 2
4 3
5 3
6 3
3 4
1->(1,2,3)
2->(4,3)
3->(4,5,6)
4->(3)
3 3 2
2 3
3 1
*/
}
}
public class QuickUnionUF {
private int[] componentID;
private int count; // number of components
public QuickUnionUF(int n)
{
if(n<0) throw new IllegalArgumentException();
this.count=n;
this.componentID=new int[n];
for(int i=0;i<n;i++)
{
componentID[i]=i;
}
}
//連接兩個節點
void union(int p,int q) //O(N)
{
int rootP=this.find(p);
int rootQ=this.find(q);
if(rootP==rootQ)
return;
this.componentID[rootP]=rootQ;
count--;
}
//在查找p節點所屬組份ID過程中會將實際上同屬於一個組份的不同ID修改成相同
int find(int p) //O(N)
{
int n=this.componentID.length;
if(p<0||p>=n)
throw new IllegalArgumentException("index " + p + " is not between 0 and " + (n-1));
while(p!=this.componentID[p])
{
this.componentID[p]=componentID[componentID[p]];
p=componentID[p];
}
return p;
}
boolean isConnected(int p,int q) //O(N)
{
int n=this.componentID.length;
if(p<0 || p>=n || q<0 || q>=n)
throw new IllegalArgumentException("index " + p +" or "+q+ " is not between 0 and " + (n-1));
return this.find(p)==this.find(q);
}
int count() //返回組份數
{
return this.count;
}
}