并查集问题

并查集问题指的是告诉你许多组两点之间的连接状态,要求某两点是否相连或者求有多少个连通图。

这种问题的求解是比较模板化的,关键在于建立find函数和union函数。find函数的主要作用是找到一个节点的根节点,union函数的作用是将某两个点的根节点相连。

主要的解题步骤如下:

  1. 建立一个长度等于节点数的root数组和rank数组,root[i]=i,rank[i]=1.
  2. 创建一个递归find函数,当x==root[x]时返回x,否则就root[x]=find(root[x]),同时改变rank数组rank[x]=rank[root[x]]+1;
  3. 创建union(x,y)函数,当find(x)!=find(y),如果将秩小的一边连在秩大的一边上。

省份数量

这题除了上述的解题步骤以外,需要注意的就是邻接矩阵实际上只有对角线以上(不包括对角线)的部分是有用的,所以遍历的时候只要遍历这部分就行了。 

public class Solution {
    int[] root;
    int[] rank;
    public int FindCircleNum(int[][] isConnected) {
        root=new int[isConnected.Length];
        rank=new int[isConnected.Length];
        for(int i=0;i<isConnected.Length;i++)
        {root[i]=i;rank[i]=1;}
        for(int i=0;i<isConnected.Length-1;i++)
        for(int j=i+1;j<isConnected.Length;j++)//只遍历邻接矩阵的上三角
        if(isConnected[i][j]==1)
        union(i,j);
        Hashtable hash=new Hashtable();
        int res=0;
        for(int i=0;i<isConnected.Length;i++)
        {
            int temp=find(i);
            if(!hash.ContainsKey(temp))
            {
                hash.Add(temp,null);
                res++;
            }
        }
        return res;
    }
    public int find(int x)
    {
        if(x==root[x])
        return x;
        root[x]=find(root[x]);
        rank[x]=rank[root[x]]+1;
        return root[x];
    }
    public void union(int x,int y)
    {
        int rootX=find(x);
        int rootY=find(y);
        if(rootX!=rootY)
        {
            if(rank[rootX]>=rank[rootY])
                root[rootY]=rootX;
            else
                root[rootX]=rootY;
        }
    } 
}

朋友圈

现在有 10^5 个用户,编号为 1- 10^5,现在已知有 m 对关系,每一对关系给你两个数 x 和 y ,代表编号为 x 的用户和编号为 y 的用户是在一个圈子中,例如: A 和 B 在一个圈子中, B 和 C 在一个圈子中,那么 A , B , C 就在一个圈子中。现在想知道最多的一个圈子内有多少个用户。

 这题比较麻烦的地方在于用户的编号并不一定是稠密排列的,所以root和rank数组只能用哈希表来表示,并且在寻找最大值时需要用到Keys和Values属性来遍历,此外,在利用这两个属性进行遍历时由于要用find函数,会改变哈希表本身,这样会报错,所以还需要一个额外的哈希表来存储有哪些用户编号。

 

using System;
using System.Collections;
using System.Collections.Generic;

class binchaji
{
    Dictionary<int, int> root;
    Dictionary<int, int> rank;
    public void maxC(int n)
    {
        root = new Dictionary<int, int>();
        rank = new Dictionary<int, int>();
        Hashtable hash = new Hashtable();
        while (n > 0)
        {
            string str = Console.ReadLine();
            int x = int.Parse(str.Split(' ')[0]);
            int y = int.Parse(str.Split(' ')[1]);
            if (!root.ContainsKey(x))
            { root.Add(x, x); rank.Add(x, 1); hash.Add(x, null); }
            if (!root.ContainsKey(y))
            { root.Add(y, y); rank.Add(y, 1); hash.Add(y, null); }
            union(x, y);
            n--;
        }
        Dictionary<int, int> max = new Dictionary<int, int>();
        ICollection keys = hash.Keys;
        foreach(int key in keys)
        {
            if (!max.ContainsKey(find(key)))
                max.Add(root[key], 1);
            else
                max[root[key]]++;
        }
        int MAX = 0;
        ICollection values = max.Values;
        foreach (int value in values)
        {
            if (MAX < value)
                MAX = value;
        }
        Console.WriteLine(MAX);
    }
    public int find(int x)
    {
        if (x == root[x])
            return x;
        root[x] = find(root[x]);
        rank[x] = rank[root[x]] + 1;
        return root[x];
    }
    public void union(int x, int y)
    {
        int rootX = find(x);
        int rootY = find(y);
        if (rootX != rootY)
        {
            if (rank[rootX] >= rank[rootY])
                root[rootY] = rootX;
            else
                root[rootX] = rootY;
        }
    }
    static void Main()
    {
        binchaji b = new binchaji();
        int t = int.Parse(Console.ReadLine());
        while (t > 0)
        {
            int n = int.Parse(Console.ReadLine());
            b.maxC(n);
            t--;
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值