华为OD机试 - 最长广播响应 - 广度优先搜索(Python/JS/C/C++ 2024 E卷 200分)

在这里插入图片描述

华为OD机试 2024E卷题库疯狂收录中,刷题点这里

专栏导读

本专栏收录于《华为OD机试真题(Python/JS/C/C++)》

刷的越多,抽中的概率越大,私信哪吒,备注华为OD,加入华为OD刷题交流群,每一题都有详细的答题思路、详细的代码注释、3个测试用例、为什么这道题采用XX算法、XX算法的适用场景,发现新题目,随时更新,全天CSDN在线答疑。

一、题目描述

某通信网络中有N个网络结点,用1到N进行标识。

网络中的结点互联互通,且结点之间的消息传递会有时延, 相连结点的时延均为一个时间单位。

现给定网络结点的连接关系列表link[i]=(u,v),其中u和v表示两网络结点。

当指定一个结点向其他结点进行广播,所有被广播结点收到消息后都会在原路径上回复一条响应消息,请计算发送结点至少需要等待几个时间单位才能收到所有被广播结点的响应消息。

注:

  1. N的取值范围为[1,100];
  2. 连接关系link的长度不超过3000,且1 <= u,v <= N;
  3. 网络中任意结点均是可达的;

二、输入描述

输入的第一行为两个正整数,分别表示网络结点的个数N,以及时延列表的长度T;

接下来的T行输入,表示结点间的连接关系列表;

最后一行的输入为一个正整数,表示指定的广播结点序号;

三、输出描述

输出一个整数,表示发送结点接收到所有响应消息至少需要等待的时长。

四、测试用例

测试用例1:

1、输入

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

2、输出

4

3、说明

结点2到5的最小时延为2, 到剩余结点的最小时延均为1,所以至少要等待2*2=4s。

测试用例2:

1、输入

3 2
1 2
2 3
1

2、输出

4

3、说明

五、解题思路

1、BFS(广度优先搜索)

用于计算从广播结点S到所有其他结点的最短距离。

适用于无权图(每条边的权重相同),能够确保找到最短路径。

在得到所有结点的最短距离后,找到其中的最大值,即为需要等待的响应时间的半值。
响应时间为该最大值的两倍。

通过高效的数据结构(如HashMap和Queue)和广度优先搜索算法,准确地从给定的连接关系列表中构建通信网络,并计算从指定广播结点到所有其他结点的最短距离。通过找到最大距离,进而计算出最少需要等待的时间单位,确保所有响应消息均能及时返回。

2、具体步骤:

  1. 输入读取:
    • 使用 Scanner 从标准输入读取网络结点的个数 N 和连接关系列表的长度 T。
    • 读取接下来的 T 行,每行包含两个字符串 u 和 v,表示结点 u 和结点 v 之间有一条无向边。
    • 使用邻接表(Map<String, List> adjacencyList)来表示网络图,键为结点标识符(字符串),值为邻接结点的列表。
  2. 邻接表构建:
    • 对于每条边 u-v,在 adjacencyList 中添加双向连接。
    • 使用 putIfAbsent 方法确保每个结点都有一个初始化的邻接列表。
  3. BFS算法计算最短距离:
    • 使用一个距离Map distanceMap 来记录从结点 S 到每个结点的最短距离,初始时只有结点 S 被访问,距离为 0。
    • 使用一个队列 Queue queue 进行BFS遍历,从结点 S 开始,将其加入队列。
    • 依次访问队列中的结点,遍历其所有邻接结点。如果邻接结点尚未被访问,则更新其距离并加入队列。
  4. 计算响应时间:
    • 遍历 distanceMap 中的所有结点,找到除 S 自身外的最大距离 maxDistance。
    • 响应时间为 2 * maxDistance,因为响应消息需要沿着原路径返回。
  5. 特殊情况处理:
    • 如果广播结点是唯一的结点(N=1),则无需等待,响应时间为 0。
    • 如果所有其他结点的距离为 0(即仅有广播结点被访问),也输出 0。
  6. 输出结果:
    • 输出计算得到的响应时间。

六、Python算法源码

# 导入所需的模块
import sys
from collections import deque

def main():
    # 读取所有输入并分割成列表
    input = sys.stdin.read().split()
    idx = 0  # 输入索引

    # 读取结点数N和连接关系数T
    N = int(input[idx])  # 网络结点的个数
    idx += 1
    T = int(input[idx])  # 连接关系列表的长度
    idx += 1

    # 构建邻接表表示的图,使用字典存储每个结点的邻接结点列表
    adjacency_list = {}
    for _ in range(T):
        u = input[idx]  # 结点u
        idx += 1
        v = input[idx]  # 结点v
        idx += 1

        # 如果结点u尚未在邻接表中,初始化其邻接列表
        if u not in adjacency_list:
            adjacency_list[u] = []
        # 如果结点v尚未在邻接表中,初始化其邻接列表
        if v not in adjacency_list:
            adjacency_list[v] = []

        # 添加双向边,因为网络是无向的
        adjacency_list[u].append(v)
        adjacency_list[v].append(u)

    # 读取指定的广播结点S
    S = input[idx]
    idx += 1

    # 使用BFS算法计算从结点S到所有其他结点的最短距离
    distance_map = {}  # 存储结点到S的最短距离
    queue = deque()    # BFS队列

    # 将广播结点S加入队列,并设置其距离为0
    queue.append(S)
    distance_map[S] = 0

    while queue:
        current = queue.popleft()  # 当前访问的结点
        current_distance = distance_map[current]  # 当前结点到S的距离

        # 遍历当前结点的所有邻接结点
        if current in adjacency_list:
            for neighbor in adjacency_list[current]:
                # 如果邻接结点尚未被访问
                if neighbor not in distance_map:
                    distance_map[neighbor] = current_distance + 1  # 更新距离
                    queue.append(neighbor)  # 将邻接结点加入队列

    # 计算所有响应消息的到达时间,即2倍的最短距离
    # 需要找到所有结点(除S自身)的最短距离中的最大值
    max_distance = 0
    for node, dist in distance_map.items():
        if node == S:
            continue  # 不需要考虑自身
        if dist > max_distance:
            max_distance = dist

    # 特殊情况处理:
    # 如果广播结点是唯一的结点,或者所有其他结点都与S相同
    if N == 1 or max_distance == 0:
        print(0)  # 无需等待
    else:
        # 响应时间为2倍的最大最短距离
        response_time = 2 * max_distance
        print(response_time)  # 输出结果

if __name__ == "__main__":
    main()

七、JavaScript算法源码

// 定义节点类,表示网络中的每个节点
class Node {
    constructor(address, value, next) {
        this.address = address; // 节点地址
        this.value = value;     // 节点值
        this.next = next;       // 下一个节点的地址
    }
}

// 主函数
function main() {
    const fs = require('fs');
    // 读取所有输入并分割成数组
    const input = fs.readFileSync('/dev/stdin').toString().trim().split(/\s+/);
    let idx = 0; // 输入索引

    // 读取结点数N和连接关系数T
    const N = parseInt(input[idx++]); // 网络结点的个数
    const T = parseInt(input[idx++]); // 连接关系列表的长度

    // 构建邻接表表示的图,使用对象存储每个结点的邻接结点列表
    // 键为结点标识符(字符串),值为邻接结点的数组
    const adjacencyList = {};

    for (let i = 0; i < T; i++) {
        const u = input[idx++]; // 结点u
        const v = input[idx++]; // 结点v

        // 如果结点u尚未在邻接表中,初始化其邻接列表
        if (!(u in adjacencyList)) {
            adjacencyList[u] = [];
        }
        // 如果结点v尚未在邻接表中,初始化其邻接列表
        if (!(v in adjacencyList)) {
            adjacencyList[v] = [];
        }

        // 添加双向边,因为网络是无向的
        adjacencyList[u].push(v);
        adjacencyList[v].push(u);
    }

    // 读取指定的广播结点S
    const S = input[idx++];

    // 使用BFS算法计算从结点S到所有其他结点的最短距离
    const distanceMap = {}; // 存储结点到S的最短距离
    const queue = [];        // BFS队列

    // 将广播结点S加入队列,并设置其距离为0
    queue.push(S);
    distanceMap[S] = 0;

    while (queue.length > 0) {
        const current = queue.shift(); // 当前访问的结点
        const currentDistance = distanceMap[current]; // 当前结点到S的距离

        // 遍历当前结点的所有邻接结点
        if (current in adjacencyList) {
            for (const neighbor of adjacencyList[current]) {
                // 如果邻接结点尚未被访问
                if (!(neighbor in distanceMap)) {
                    distanceMap[neighbor] = currentDistance + 1; // 更新距离
                    queue.push(neighbor); // 将邻接结点加入队列
                }
            }
        }
    }

    // 计算所有响应消息的到达时间,即2倍的最短距离
    // 需要找到所有结点(除S自身)的最短距离中的最大值
    let maxDistance = 0;
    for (const [node, dist] of Object.entries(distanceMap)) {
        if (node === S) {
            continue; // 不需要考虑自身
        }
        if (dist > maxDistance) {
            maxDistance = dist;
        }
    }

    // 特殊情况处理:
    // 如果广播结点是唯一的结点,或者所有其他结点都与S相同
    if (N === 1 || maxDistance === 0) {
        console.log(0); // 无需等待
    } else {
        // 响应时间为2倍的最大最短距离
        const responseTime = 2 * maxDistance;
        console.log(responseTime); // 输出结果
    }
}

// 执行主函数
main();

八、C算法源码

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

// 定义最大地址长度
#define MAX_ADDR_LEN 20

// 定义邻接表的最大结点数
#define MAX_NODES 100

// 定义邻接表结构体
typedef struct Node {
    char address[MAX_ADDR_LEN]; // 节点地址
    int value;                   // 节点值(本问题中未使用,可以忽略)
    char next[MAX_ADDR_LEN];    // 下一个节点的地址(本问题中未使用,可以忽略)
} Node;

// 定义队列结构体
typedef struct Queue {
    char elements[MAX_NODES][MAX_ADDR_LEN]; // 队列元素
    int front;   // 队首指针
    int rear;    // 队尾指针
} Queue;

// 初始化队列
void initQueue(Queue* q) {
    q->front = 0;
    q->rear = 0;
}

// 检查队列是否为空
int isEmpty(Queue* q) {
    return q->front == q->rear;
}

// 入队
void enqueue(Queue* q, const char* addr) {
    strcpy(q->elements[q->rear], addr);
    q->rear++;
}

// 出队
void dequeue(Queue* q, char* addr) {
    strcpy(addr, q->elements[q->front]);
    q->front++;
}

int main() {
    int N, T;
    // 读取结点数N和连接关系数T
    scanf("%d %d", &N, &T);

    // 构建邻接表表示的图,使用二维数组存储邻接结点
    // adjacencyList[i] 存储结点i的邻接结点列表
    // 使用数组的字符串存储结点地址
    char adjacencyList[MAX_NODES][MAX_NODES][MAX_ADDR_LEN];
    int adjacencyCount[MAX_NODES]; // 每个结点的邻接结点数量

    // 初始化邻接表
    for(int i = 0; i < MAX_NODES; i++) {
        adjacencyCount[i] = 0;
    }

    // 为了映射结点地址到索引,使用一个简单的映射
    // nodeIndex存储每个结点地址对应的索引
    char nodeAddresses[MAX_NODES][MAX_ADDR_LEN];
    int nodeCount = 0;

    // 读取T条连接关系
    for(int i = 0; i < T; i++) {
        char u[MAX_ADDR_LEN], v[MAX_ADDR_LEN];
        scanf("%s %s", u, v);

        // 查找或添加结点u
        int u_idx = -1;
        for(int j = 0; j < nodeCount; j++) {
            if(strcmp(nodeAddresses[j], u) == 0) {
                u_idx = j;
                break;
            }
        }
        if(u_idx == -1) {
            strcpy(nodeAddresses[nodeCount], u);
            u_idx = nodeCount;
            nodeCount++;
        }

        // 查找或添加结点v
        int v_idx = -1;
        for(int j = 0; j < nodeCount; j++) {
            if(strcmp(nodeAddresses[j], v) == 0) {
                v_idx = j;
                break;
            }
        }
        if(v_idx == -1) {
            strcpy(nodeAddresses[nodeCount], v);
            v_idx = nodeCount;
            nodeCount++;
        }

        // 添加双向边
        strcpy(adjacencyList[u_idx][adjacencyCount[u_idx]], v);
        adjacencyCount[u_idx]++;
        strcpy(adjacencyList[v_idx][adjacencyCount[v_idx]], u);
        adjacencyCount[v_idx]++;
    }

    // 读取指定的广播结点S
    char S[MAX_ADDR_LEN];
    scanf("%s", S);

    // BFS初始化
    int visited[MAX_NODES];
    int distance_map[MAX_NODES];
    for(int i = 0; i < nodeCount; i++) {
        visited[i] = 0;
        distance_map[i] = -1;
    }

    // 查找S的索引
    int S_idx = -1;
    for(int i = 0; i < nodeCount; i++) {
        if(strcmp(nodeAddresses[i], S) == 0) {
            S_idx = i;
            break;
        }
    }

    if(S_idx == -1) {
        // 广播结点S不存在
        printf("0\n");
        return 0;
    }

    // 初始化队列
    Queue q;
    initQueue(&q);
    enqueue(&q, S);
    visited[S_idx] = 1;
    distance_map[S_idx] = 0;

    // BFS遍历
    while(!isEmpty(&q)) {
        char current[MAX_ADDR_LEN];
        dequeue(&q, current);

        // 查找当前结点的索引
        int current_idx = -1;
        for(int i = 0; i < nodeCount; i++) {
            if(strcmp(nodeAddresses[i], current) == 0) {
                current_idx = i;
                break;
            }
        }

        if(current_idx == -1) {
            continue;
        }

        // 遍历所有邻接结点
        for(int i = 0; i < adjacencyCount[current_idx]; i++) {
            char neighbor[MAX_ADDR_LEN];
            strcpy(neighbor, adjacencyList[current_idx][i]);

            // 查找邻接结点的索引
            int neighbor_idx = -1;
            for(int j = 0; j < nodeCount; j++) {
                if(strcmp(nodeAddresses[j], neighbor) == 0) {
                    neighbor_idx = j;
                    break;
                }
            }

            if(neighbor_idx == -1 || visited[neighbor_idx]) {
                continue;
            }

            // 标记为已访问并更新距离
            visited[neighbor_idx] = 1;
            distance_map[neighbor_idx] = distance_map[current_idx] + 1;
            enqueue(&q, neighbor);
        }
    }

    // 找到最大距离
    int max_distance = 0;
    for(int i = 0; i < nodeCount; i++) {
        if(i == S_idx) {
            continue; // 不需要考虑自身
        }
        if(distance_map[i] > max_distance) {
            max_distance = distance_map[i];
        }
    }

    // 计算响应时间
    int response_time = 2 * max_distance;

    // 特殊情况处理
    if(N == 1 || max_distance == 0) {
        printf("0\n"); // 无需等待
    }
    else {
        printf("%d\n", response_time); // 输出结果
    }

    // 释放动态分配的内存(本程序中未使用动态分配,故不需要)
    return 0;
}

九、C++算法源码

#include <iostream>
#include <unordered_map>
#include <vector>
#include <queue>
#include <string>
#include <algorithm>

using namespace std;

/**
 * 通信网络广播响应时间计算程序
 *
 * 该程序用于计算在一个通信网络中,指定结点向所有其他结点广播消息后,
 * 需要等待多少时间单位才能收到所有被广播结点的响应消息。
 *
 * 题目描述:
 * - 有N个网络结点,用唯一的标识符进行标识(可以是字符串或整数)。
 * - 结点之间通过无向边连接,且每条边的时延为1个时间单位。
 * - 指定一个结点作为广播结点,向所有其他结点广播消息。
 * - 被广播结点收到消息后,会沿着原路径回复响应消息。
 * - 需要计算发送结点至少需要等待几个时间单位才能收到所有响应消息。
 *
 * 输入描述:
 * - 第一行:两个正整数N(结点数,1 ≤ N ≤ 100)和T(连接关系列表长度,0 ≤ T ≤ 3000)。
 * - 接下来的T行:每行包含两个字符串u和v,表示结点u和结点v之间有一条无向边。
 * - 最后一行:一个字符串S,表示指定的广播结点序号。
 *
 * 输出描述:
 * - 一个整数,表示发送结点接收到所有响应消息至少需要等待的时长。
 *
 * 示例测试用例:
 *
 * 测试用例1:
 * 输入:
 * 5 7
 * 1 4
 * 2 1
 * 2 3
 * 2 4
 * 3 4
 * 3 5
 * 4 5
 * 2
 * 输出:
 * 4
 *
 * 说明:
 * - 网络结构:
 *   1-4
 *   2-1
 *   2-3
 *   2-4
 *   3-4
 *   3-5
 *   4-5
 * - 从结点2出发:
 *   到结点1的距离:1
 *   到结点3的距离:1
 *   到结点4的距离:1
 *   到结点5的距离:2
 * - 最大距离为2,响应时间为4。
 */

int main() {
    ios::sync_with_stdio(false); // 关闭同步,加快输入输出速度
    cin.tie(0); // 取消cin的绑定,提高效率

    int N, T; // N: 网络结点的个数,T: 连接关系列表的长度
    cin >> N >> T; // 读取N和T

    // 使用哈希表构建邻接表,键为结点标识符,值为邻接结点的列表
    unordered_map<string, vector<string>> adjacencyList;

    // 读取T条连接关系,构建邻接表
    for(int i = 0; i < T; ++i){
        string u, v;
        cin >> u >> v; // 读取两个结点u和v
        adjacencyList[u].push_back(v); // 添加v到u的邻接列表
        adjacencyList[v].push_back(u); // 添加u到v的邻接列表,因为是无向边
    }

    string S; // 指定的广播结点
    cin >> S; // 读取广播结点S

    // 使用广度优先搜索(BFS)计算从结点S到所有其他结点的最短距离
    unordered_map<string, int> distanceMap; // 存储从S到每个结点的最短距离
    queue<string> q; // BFS队列

    // 初始化BFS
    q.push(S); // 将广播结点S加入队列
    distanceMap[S] = 0; // S到自己的距离为0

    while(!q.empty()){
        string current = q.front(); // 取出队列头部结点
        q.pop(); // 移除队列头部结点
        int currentDistance = distanceMap[current]; // 获取当前结点到S的距离

        // 遍历当前结点的所有邻接结点
        for(auto &neighbor : adjacencyList[current]){
            // 如果邻接结点尚未被访问
            if(distanceMap.find(neighbor) == distanceMap.end()){
                distanceMap[neighbor] = currentDistance + 1; // 更新距离
                q.push(neighbor); // 将邻接结点加入队列
            }
        }
    }

    // 计算所有响应消息的到达时间,即2倍的最短距离
    int maxDistance = 0; // 最大距离初始化为0

    // 遍历所有结点,找到最大距离
    for(auto &entry : distanceMap){
        string node = entry.first;
        int dist = entry.second;
        if(node == S) continue; // 忽略广播结点S自身
        if(dist > maxDistance){
            maxDistance = dist; // 更新最大距离
        }
    }

    // 特殊情况处理:
    // 如果网络中只有一个结点(N=1),则无需等待,响应时间为0
    if(N == 1){
        cout << 0;
        return 0;
    }

    // 响应时间为2倍的最大最短距离
    int responseTime = 2 * maxDistance;

    // 输出结果
    cout << responseTime;

    return 0; // 程序结束
}


🏆下一篇:华为OD机试真题 - 简易内存池(Python/JS/C/C++ 2024 E卷 200分)

🏆本文收录于,华为OD机试真题(Python/JS/C/C++)

刷的越多,抽中的概率越大,私信哪吒,备注华为OD,加入华为OD刷题交流群,每一题都有详细的答题思路、详细的代码注释、3个测试用例、为什么这道题采用XX算法、XX算法的适用场景,发现新题目,随时更新,全天CSDN在线答疑。

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

哪 吒

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值