并查集练习-小团的配送团队

对并查集还不太了解的同学可以先学习下【算法与数据结构】—— 并查集

1、题目(小团的配送团队)

​ 小团是美团外卖的区域配送负责人,众所周知,外卖小哥一般都会同时配送若干单,小团在接单时希望把同一个小区的单子放在一起,然后由一名骑手统一配送。但是由于订单是叠在一起的,所以,他归类订单时只能知道新订单和已有的某个订单的小区是相同的,他觉得这样太麻烦了,所以希望你帮他写一个程序解决这个问题。

​ 即给出若干个形如a b的关系,表示a号订单和b号订单是同一个小区的 ,请你把同一个小区的订单按照编号顺序排序,并分行输出,优先输出最小的订单编号较小的小区订单集合。订单的编号是1到n。(可能存在同时出现a b和b a这样的关系,也有可能出现a a这样的关系)

2、输入描述

输入第一行是两个正整数n,m,表示接受的订单数量和已知的关系数量。(1<=n,m<=10000)接下来有m行,每行两个正整数a和b,表示a号订单和b号订单属于同一个小区(1<=a,b<=n);

3、输出描述

输出第一行包含一个整数x,表示这些订单共来自x个不同的小区。接下来的输出包含x行,每行表示输出若干个订单编号,表示这些订单属于同一个小区,按照订单编号升序输出。优先输出最小的订单编号较小的小区。

4、示例

输入

5 5
1 2
2 2
3 1
4 2
5 4

输出

1
1 2 3 4 5

5、解题思路

并查集

6、题解

import java.util.*;

public class Main{
    private static int[] father;

    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        int n = input.nextInt();
        int m = input.nextInt();
        father = new int[n + 1];
        for (int i = 0; i < n + 1; i++) {
            father[i] = i;
        }
        int city1 , city2;
        for (int i = 0; i < m; i++) {
            city1 = input.nextInt();
            city2 = input.nextInt();
            union(city1, city2);
        }
        Map<Integer, TreeSet<Integer>> res = new TreeMap<>();
        for (int i = 1; i <= n; i++) {
            int fa = findFather(i);
            TreeSet<Integer> tempSet = res.getOrDefault(fa, new TreeSet<>());
            tempSet.add(i);
            res.put(fa, tempSet);
        }
        System.out.println(res.size());
        Set<Integer> keySet = res.keySet();
        for (int key: keySet) {
            Set<Integer> tempSet = res.get(key);
            int size = 0;
            for (int id: tempSet) {
                System.out.print(id);
                size++;
                if (size < tempSet.size()) System.out.print(" ");
                else System.out.println();
            }
        }
    }

    public static int findFather(int a) {
        int x = a;
        while (x != father[x]) x = father[x];
        while (a != father[a]) {
            int z = a;
            a = father[a];
            father[z] = x;
        }
        return x;
    }

    public static void union(int a, int b) {
        int fa = findFather(a);
        int fb = findFather(b);
        if (fa != fb) {
            //father[fa] = fb;  //若要保证含有最小单号的小区先输出,那么久不能随便合并集合了,要将小的那个根作为整个集合的根
            if (fa < fb) {
                father[fb] = fa;
            } else {
                father[fa] = fb;
            }
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值