题目
Today is Ignatius’ birthday. He invites a lot of friends. Now it’s dinner time. Ignatius wants to know how many tables he needs at least. You have to notice that not all the friends know each other, and all the friends do not want to stay with strangers.
One important rule for this problem is that if I tell you A knows B, and B knows C, that means A, B, C know each other, so they can stay in one table.
For example: If I tell you A knows B, B knows C, and D knows E, so A, B, C can stay in one table, and D, E have to stay in the other one. So Ignatius needs 2 tables at least.
题目传送门
Input
The input starts with an integer T(1<=T<=25) which indicate the number of test cases. Then T test cases follow. Each test case starts with two integers N and M(1<=N,M<=1000). N indicates the number of friends, the friends are marked from 1 to N. Then M lines follow. Each line consists of two integers A and B(A!=B), that means friend A and friend B know each other. There will be a blank line between two cases.
Output
For each test case, just output how many tables Ignatius needs at least. Do NOT print any blanks.
大概意思就是A认识B,B认识C,也就意味着A认识C。这样他们就可以坐在一个桌子上。问你输入T个测试例子,每个测试例子的第一行是N和M两个数,N表示来的人数,M表示他们之间有多少人是认识的。给你这一系列的数据后,问你要多少个桌子才能坐得下所有人?
思路
其实就是一个简单的并查集,先建立一个数组,并且将每个人都分在同一个桌子,每次输入一对关系的时候,就判断一下他们是否在同一个父节点上面,即是否在同一桌,如果是,那就继续,不是的话,那么需要合并其中一个到另外的一个桌子。依次询问,直到结束。
代码
import java.util.Scanner;
public class Main {
static int father[]=new int[1005];
public static void main(String[] args) {
Scanner reader=new Scanner(System.in);
int T=reader.nextInt();//测试例子数目
//进行T次询问
for (int g=0;g<T;++g)
{
int N=reader.nextInt();//原始的人数
//初始化,每个人都是自成一派
for (int i=1;i<=N;++i)
father[i]=i;
int M=reader.nextInt();//相关联的次数
for (int i=0;i<M;++i)
{
int a=reader.nextInt();
int b=reader.nextInt();
if (findfather(a)!=findfather(b))
{
union(a,b);
}
}
int ans=0;
for (int i=1;i<=N;++i)
if (father[i]==i)
++ans;
System.out.println(ans);
}
}
//寻找每个人的根节点,并且进行路径压缩,即当前点的父节点不是她自己,那么就通过他的父节点继续寻找父节点的父节点,直到找到为止,并且将当前的父节点修改为最大的父节点,压缩路径,使得每个结点都直接跟父节点相关联
private static int findfather(int a) {
if (a==father[a])
return a;
father[a]=findfather(father[a]);
return father[a];
}
//路径压缩,先寻找到两个点的父节点,如果两个点的父节点不一样,那么需要将其中的一个父节点改变为另一个的父节点。
private static void union(int a, int b) {
a=findfather(a);
b=findfather(b);
if (a!=b)
father[b]=a;
}
}
结果
就是一个并查集的简单应用,复习一下。