How Many Tables——HDU 1213

该博客介绍了一个关于朋友聚会分桌的问题,利用并查集算法解决。给定人数N和朋友关系M,如果A认识B,B认识C,三人可以同桌。任务是确定最少需要多少张桌子。代码实现包括并查集的路径压缩和合并操作,通过输入的M对关系判断朋友是否已分配在同一桌,最后输出所需桌子数量。
摘要由CSDN通过智能技术生成

题目

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;
    }
}

结果

在这里插入图片描述
就是一个并查集的简单应用,复习一下。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值