并查集详解(二)

前几天的2019年字节跳动第二次笔试第一道题属于并查集问题,现在补充学习并记录一下。

题目内容如下:

1.Bytedance Efficiency Engineering团队在8月20日搬入了学清嘉创大厦。为了庆祝乔迁之喜,字节君决定邀请整个EE团队,举办一个大型团建游戏-字节跳动大闯关。可是遇到了一个问题:EE团队共有n个人,大家都比较害羞,不善于与陌生人交流。这n个人每个人都想字节君提供了自己认识的人的名字,不包括自己。如果A的名单里有B,或B的名单里有A,则代表AB相互认识。同时如果A认识B,B认识C,则代表A与C也会很快的认识,毕竟通过B的介绍,两个人就可以很快互相认识了。

为了大闯关游戏可以更好的团队协作、气氛更活跃,并使得团队中的人可以尽快的相互了解、认识和交流,字节君决定根据这个名单将团队分为m组,每组人数可以不同,但组内的任何一个人都与组内的其他所有人直接或间接的认识和交流。如何确定一个方案,使得团队可以分成m组,并且这个m尽可能的小呢?

输入描述:

第一行一个整数n,代表有n个人,从1开始编号

接下来有n 行,第x+1行代表编号为x 的人认识的人的编号k(1<=k<=n),每个人的名单以0代表结束。

输出描述:

一个整数m,代表可以分的最小的组的个数。

示例

输入

10

0

5 3 0

8 4 0

9 0

9 0

3 0

0

7 9 0

0

9 7 0

输出

2

说明

1号同学孤独的自己一个组,他谁也不认识,也没有人认识他。其他所有人均刻意直接或间接的认识,分在同一组。

根据并查集原理编写代码如下:

int find(int x,vector<int>&Symbol)
{
    int r=x;
    while(r!=Symbol[r])
        r=Symbol[r];
    int i=x,j;
    while(Symbol[i]!=r)
    {
        j=Symbol[i];
        Symbol[i]=r;
        i=j;
    }
    return r;
}
void mix(int x,int y,vector<int>&Symbol)
{
    int fx=find(x,Symbol),fy=find(y,Symbol);
    if(fx!=fy)
    {
        Symbol[fy]=fx;
    }
}
int main()
{
    int n;
    cin>>n;
    vector<vector<int>>Nums;
    vector<int>Symbol(n+1);//用于标记点属于某一阵营
    for (int i=0;i<n;i++)
    {
        vector<int>ptemp;
        int nTemp;
        do 
        {
            cin>>nTemp;
            ptemp.push_back(nTemp);
        } while (nTemp!=0);
        Nums.push_back(ptemp);
    }
    for (int i=1;i<=n;i++)//初始化
    {
        Symbol[i]=i;
    }
    for (int i=1;i<=n;i++)//整理数据
    {
        for (int j=0;j<Nums[i-1].size();j++)
        {
            if (Nums[i-1][j]!=0)
            {
                mix(i,Nums[i-1][j],Symbol);
            }
        }
    }
    vector<bool>bSymbol(n+1);
    for(int i=1;i<=n;i++)          //标记根结点
    {
        bSymbol[find(i,Symbol)]=1;
    }
    int ans=0;
    for(int i=1;i<=n;i++)
        if(bSymbol[i])
            ans++;
    printf("%d\n",ans);

return 0;

}

#include <iostream>
#include <vector>
#include<algorithm>
using namespace std;
int find(int x,vector<int>&Symbol)
{
	int r=x;
	while(r!=Symbol[r])
		r=Symbol[r];
	int i=x,j;
	while(Symbol[i]!=r)
	{
		j=Symbol[i];
		Symbol[i]=r;
		i=j;
	}
	return r;
}
void mix(int x,int y,vector<int>&Symbol)
{
	int fx=find(x,Symbol),fy=find(y,Symbol);
	if(fx!=fy)
	{
		Symbol[fy]=fx;
	}
}
int main()
{
	int n;
	cin>>n;
	vector<vector<int>>Nums;
	vector<int>Symbol(n+1);//用于标记点属于某一阵营
	for (int i=0;i<n;i++)
	{
		vector<int>ptemp;
		int nTemp;
		do 
		{
			cin>>nTemp;
			ptemp.push_back(nTemp);
		} while (nTemp!=0);
		Nums.push_back(ptemp);
	}
	for (int i=1;i<=n;i++)//初始化
	{
		Symbol[i]=i;
	}
	for (int i=1;i<=n;i++)//整理数据
	{
		for (int j=0;j<Nums[i-1].size();j++)
		{
			if (Nums[i-1][j]!=0)
			{
				mix(i,Nums[i-1][j],Symbol);
			}
		}
	}
	vector<bool>bSymbol(n+1);
	for(int i=1;i<=n;i++)          //标记根结点
	{
		bSymbol[find(i,Symbol)]=1;
	}
	int ans=0;
	for(int i=1;i<=n;i++)
		if(bSymbol[i])
			ans++;
	printf("%d\n",ans); 
  return 0;
}

猜你喜欢

转载自blog.csdn.net/hi_baymax/article/details/82149576