1. 程式人生 > 其它 >並查集(Disjoint Set)

並查集(Disjoint Set)

解決的問題

查詢圖是否成環

理解過程

思想

右邊圖代表著圈裡面的點是連通的
成環的標誌是:圈內某兩元素之間還有一條邊

轉化為程式碼(合併兩個圈)

利用陣列建樹,陣列元素值代表該位置的父親結點,-1代表為獨立結點

因此:
合併兩圈=把a2圖的頭結點的父親結點改為a1圖的頭結點

當發現某條邊的兩個結點的根節點是同一結點時,代表著成環了

可能會出先這種情況,複雜度變為O(n)

因此需要演算法優化:壓縮路徑

用root記錄樹的高度,
if (root[x]> root[y])
則 :y樹拼到x樹
且新root=root[x];

程式碼


#include <bits/stdc++.h>
using namespace std;
int pre[30005];
int root[35500];

int find(int x)
{
  if (pre[x] != x)
  {
    pre[x] = find(pre[x]);
  }
  return pre[x];
}
void join(int x, int y)
{
  int fx = find(x);
  int fy = find(y);
  if (fx != fy)
  {
    pre[fx] = fy;
  }
}

int main()
{
  int n,m;
  cin>>n>>m;
  for(int i=1;i<=n;i++)
  {
    pre[i]=i;
  }
  while(m--)
  {
    int k;
    cin>>k;
    int arr[30000];
    for(int i=1;i<=k;i++)
    {
      cin>>arr[i];
    }
    for(int i=2;i<=k;i++)
  {
    join(arr[i],arr[i-1]);
  }
  }
  int ans=0;
  for(int i=1;i<=n;i++)
  {
    int t=find(i);
    root[t]++;
    ans=max(root[t],ans);
  }
  cout<<ans<<endl;
  return 0;
}