华为机试:服务器广播

【编程题目 | 200分】服务器广播 [ 200 / 困难 ]

服务器广播
题目描述:

服务器连接方式包括直接相连,间接连接。A 和 B 直接连接,B 和 C 直接连接,则 A 和 C 间接连接。直接连接和间接连接都可以发送广播。

  • 给出一个 N*N 数组,代表 N 个服务器,matrix[i][j]==1,则代表 i 和 j 直接连接;
  • 不等于 1 时,代表 i 和 j 不直接连接。
  • matrix[i][i]==1,即自己和自己直接连接。matrix[i][j]==matrix[j][i]。

计算初始需要给几台服务器广播,才可以使每个服务器都收到广播。

输入描述

输入为N行,每行有N个数字,为0或1,由空格分隔,构成N*N的数组,N的范围为 1<=N<=50

输出描述

输出一个数字,为需要广播的服务器数量

示例 1:
输入
1 0 0
0 1 0
0 0 1
输出
3
说明

3台服务器互不连接,所以需要分别广播这3台服务器

示例 1:
输入
1 1
1 1
输出
1
说明

2台服务器相互连接,所以只需要广播其中一台服务器

思路分析:
  1. 从第一个开始判断,依次将直连的服务器加进来
  2. 从1找到的集合中依次将直连的服务器加进来,直到集合没有变化
  3. 获取1集合中不存在的服务器,重复以上步骤
  4. 上述集合的个数,就是需要发出广播的服务器数量
参考代码

Java代码实现:

import java.util.*;

public class ServiceBroadcast {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        while (in.hasNext()) {
            String[] str = in.nextLine().split(" ");
            List<Integer> list = new ArrayList<>();
            for (int i = 0; i < str.length; i++) {  // 把第一行加入list
                list.add(Integer.parseInt(str[i]));
            }
            for (int i = 0; i < str.length - 1; i++) {  // 把剩下的行都加入list
                String[] s = in.nextLine().split(" ");
                for (int j = 0; j < s.length; j++) {
                    list.add(Integer.parseInt(s[j]));
                }
            }
            int N = str.length;
            List<List<Integer>> res = new ArrayList<>(); // 存储需要广播的服务器
            for (int i = 0; i < N; i++) {  // 每一行
                if (isContainer(res, i)) {  // 判断某个服务器是否已经存在其连通的服务器集合中
                    continue;
                }
                List<Integer> newList = new ArrayList<>();
                newList.add(i);
                int lastLength = 0;
                while (lastLength != newList.size()) { // 判断当前集合可以联通的服务器
                    for (int k = 0; k < newList.size(); k++) {
                        int x = newList.get(k);
                        for (int j = 0; j < N; j++) {
                            int index = x * (N) + j;  // 找到在对应list的索引
                            if (list.get(index).equals(1)) {
                                if (!newList.contains(j)) {
                                    newList.add(j);
                                }
                            }
                        }
                    }
                    lastLength = newList.size();
                }
                res.add(newList);
            }
            System.out.println(res.size());
        }
    }
    public static Boolean isContainer(List<List<Integer>> res, int x) {
        for (List<Integer> integers : res) {
            if (integers.contains(x)) {
                return true;
            }
        }
        return false;
    }
}

dfs:

参考下面评论区的回溯dfs代码:

import java.util.*;

public class ServiceBroadcast_dfs {
    public static int count = 0;
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        String[] str = in.nextLine().split(" ");
        int n = str.length;
        int[][] arr = new int[n][n];
        for(int i = 0; i < n; i++) {  // 把第一行加入arr
            arr[0][i] = Integer.parseInt(str[i]);
        }
        for(int i = 1; i < n; i++) {  // 把剩下的行加入arr
            String[] s = in.nextLine().split(" ");
            for(int j = 0; j < n; j++) {
                arr[i][j] = Integer.parseInt(s[j]);
            }
        }
        boolean[] visited = new boolean[n];
        for(int i = 0; i < n; i++) {
            if(!visited[i]) {
                dfs(arr, visited, i);
            }
        }
        System.out.println(count);
    }
    public static void dfs(int[][] arr, boolean[] visited, int index) {
        visited[index] = true;
        boolean flag = true;
        for (int i = index + 1; i < arr.length; i++) {
            if (arr[index][i] == 1) {
                flag = false;
                dfs(arr, visited, i);
            }
        }
        if (flag) {
            count++;
        }
    }
}

并查集

套用并查集的模板,输出并查集的个数即可。

import java.util.Scanner;

public class ServiceBroadcast_union {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        String[] str = in.nextLine().split(" ");
        int n = str.length;
        int[][] arr = new int[n][n];
        for(int i = 0; i < n; i++) {  // 把第一行加入arr
            arr[0][i] = Integer.parseInt(str[i]);
        }
        for(int i = 1; i < n; i++) {  // 把剩下的行加入arr
            String[] s = in.nextLine().split(" ");
            for(int j = 0; j < n; j++) {
                arr[i][j] = Integer.parseInt(s[j]);
            }
        }
        UF uf = new UF(n);
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                if (arr[i][j] == 1) {  // 如果距离为1,就合并到一块
                    uf.union(i, j);
                }
            }
        }
        System.out.println(uf.getCount());
    }
}
class UF {  // 并查集模板,可直接复制使用
    int count;   //连通分量个数
    int[] id;
    int[] sz;

    public UF(int n) {
        count = n;
        id = new int[n];
        sz = new int[n];
        for (int i = 0; i < n; i++) {
            id[i] = i;
            sz[i] = 1;
        }
    }

    public int getCount() {
        return count;
    }

    public int find(int p) {
        if (p != id[p]) {
            id[p] = find(id[p]);
        }
        return id[p];
    }

    public boolean union(int p, int q) {
        int pRoot = find(p);
        int qRoot = find(q);
        if (pRoot == qRoot) {
            return  false;
        }
        if (sz[pRoot] > sz[qRoot]) {
            id[qRoot] = pRoot;
            sz[pRoot] += sz[qRoot];
        } else {
            id[pRoot] = qRoot;
            sz[qRoot] += sz[pRoot];
        }
        count--;
        return true;
    }
}

并查集类问题可参考:【Leetcode】并查集(Union-Find)算法

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值