How Many Tables 普通并查集

天是伊格那丢的生日。他邀请了很多朋友。现在该吃晚饭了。伊格那丢想知道他至少需要多少张桌子。你要注意,并不是所有的朋友都认识彼此,所有的朋友都不想和陌
生人呆在一起。
这个问题的一个重要规则是如果我告诉你A认识B, B认识C,这意味着A B C彼此认识,所以它们可以留在一个表中。
例如,如果我告诉你A知道B, B知道C, D知道E,那么A, B, C可以留在一个表中,而D, E必须留在另一个表中。所以伊格那丢至少需要两张桌子。

输入以整数T(1<=T<=25)开始,表示测试用例的数量。
然后是T测试用例。
每个测试用例都以两个整数N和M开始(1<=N,M<=1000)。
N表示朋友的数量,从1到N,后面有M行。
每一行由两个整数A和B组成(A!=B),表示朋友A和朋友B认识。
两种情况之间将有一条空行。

对于每个测试用例,只输出Ignatius至少需要多少个桌子。不要打印任何空白。
input
2
5 3
1 2
2 3
4 5
father[1~5]:1->2 2->3 3->3 4->5 5->5根节点只有2个 
5 1
2 5
output
2
4

错误思路
开个father[N],默认为0,再写个初始化函数,每个案例先变0,再初始化成i,路径压缩,最后在1~n查询有多少个不同的根节点 
错因:    没有理解合并并查集的操作  

正确思路:合并并查集后再查询

#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
const int N=1001;
int father[N];
void inf(int n)//初始化 
{
	for(int i=1;i<=N;i++)	father[i]=i;
}
bool judge(int x)//判断是否为根节点 
{
	if(x==father[x]) return true;
	else return false;
}
int findFather(int x)
{
	//由于x在下面的while中会变成根结点, 因此先把原先的x保存一下
	int temp=x;
	while(x!=father[x]){//寻找根节点 
		x=father[x];
	}
	//到这里, x存放的是根结点。 下面把路径上的所有结点的father都改成根结点
	while(temp!=father[temp])
	{
		int t=temp;//因为temp要被father[temp]覆盖, 所以先保存temp的值, 以修改father[temp]
		temp=father[temp];
		father[t]=x;//将原先的结点temp的父亲改为根结点x
	}
	return x; //返回根结点
}
void Union (int a,int b)//U务必大写,因为union是个关键字 
{
	int faA=findFather(a);
	int faB=findFather(b);
	if(faA==faB)	return;//判断它们是否属于同一集合
	else{
		father[faB]=faA;//把其中一个的父亲结点指向另一个结点
	}
}
int cnt(int n)
{
	int ans=0;
	for(int i=1;i<=n;i++)
		if(judge(i))	ans++;
	return ans;
}
int main(){
	int T;cin>>T;
	while(T--)
	{
		memset(father,0,sizeof(father));
		int n,m;
		cin>>n>>m;
		inf(n);
		while(m--)
		{
			int a,b;
			cin>>a>>b;
			Union(a,b);
		}
		cout<<cnt(n)<<endl;	
	}
	return 0;
} 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值