(C卷,200分)- 电脑病毒感染(Java & JS & Python & C)

题目描述

一个局域网内有很多台电脑,分别标注为 0 ~ N-1 的数字。相连接的电脑距离不一样,所以感染时间不一样,感染时间用 t 表示。

其中网络内一台电脑被病毒感染,求其感染网络内所有的电脑最少需要多长时间。如果最后有电脑不会感染,则返回-1。

给定一个数组 times 表示一台电脑把相邻电脑感染所用的时间。

如图:path[i] = {i, j, t} 表示:电脑 i->j,电脑 i 上的病毒感染 j,需要时间 t。

输入描述

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

输出描述

2

用例

输入 4
3
2 1 1
2 3 1
3 4 1
2
输出 2
说明

第一个参数:局域网内电脑个数N,1 ≤ N ≤ 200;

第二个参数:总共多少条网络连接

第三个 2 1 1 表示2->1时间为1

第六行:表示病毒最开始所在电脑号2

题目解析

用例图示如下

病毒源头是2,其中:

2->1需要时间1

2->3需要时间1,3->4需要时间1

因此最少需要时间2才能感染所有电脑。

本题考察的是单源最短路径求解,解析可以参考:

另外,本题题目描述和用例不符。因为题目说:

一个局域网内有很多台电脑,分别标注为 0 ~ N-1 的数字。

但是题目用例,第一行给出N=4,但是第五行出现了电脑编号也是4的情况。

这影响到了下面代码中dist、visited数组长度的定义。当前代码实现以用例数据为准,即认为电脑编号是 1~N。

具体考试时需要随机应变。

JS算法源码

const rl = require("readline").createInterface({ input: process.stdin });
var iter = rl[Symbol.asyncIterator]();
const readline = async () => (await iter.next()).value;

void (async function () {
  const n = parseInt(await readline());

  // 邻接表
  const graph = {};

  const m = parseInt(await readline());
  for (let i = 0; i < m; i++) {
    // [出发点, 目标点, 出发点到达目标点的耗时]
    const [u, v, w] = (await readline()).split(" ").map(Number);

    if (graph[u]) {
      graph[u].push([v, w]);
    } else {
      graph[u] = [[v, w]];
    }
  }

  // 记录源点到其他各点的最短耗时
  // 初始时,假设源点不可达其他剩余点,即源点到达其他点的耗时无限大
  const dist = new Array(n + 1).fill(Infinity);

  // 源点
  const src = parseInt(await readline());
  // 源点到达源点的耗时为0
  dist[src] = 0;

  // needCheck中记录的其实是:已被探索过的路径的终点(路径指的是源点->终点)
  // 排序规则是,路径终点的权重(即源点->终点的耗时)越小越靠后
  const needCheck = [];
  // 初始被探索过的路径只有源点本身
  needCheck.push(src);

  // 记录对应点是否在needCheck中
  const visited = new Array(n + 1).fill(false);
  visited[src] = true;

  while (needCheck.length > 0) {
    // 取出最优路径的终点(耗时最少的路径)作为新的起点
    const cur = needCheck.pop();
    visited[cur] = false;

    // 如果cur有可达的其他点
    if (graph[cur]) {
      // v是可达的其他店
      // w是cur->v的耗时
      for (let [v, w] of graph[cur]) {
        // 那么如果从源点到cur点的耗时是dist[cur],那么源点到v点的耗时就是dist[cur] + w
        const newDist = dist[cur] + w;

        // 而源点到v的耗时之前是dist[v],因此如果newDist < dist[v],则找到更少耗时的路径
        if (dist[v] > newDist) {
          // 更新源点到v的路径,即更新v点权重
          dist[v] = newDist;

          // 如果v点不在needCheck中,则加入,因为v作为终点的路径需要加入到下一次最优路径的评比中
          if (!visited[v]) {
            visited[v] = true;
            needCheck.push(v);
            needCheck.sort((a, b) => dist[b] - dist[a]);
          }
        }
      }
    }
  }

  // dist记录的是源点到达其他各点的最短耗时,我们取出其中最大的就是源点走完所有点的最短耗时
  let ans = 0;
  for (let i = 1; i <= n; i++) {
    ans = Math.max(ans, dist[i]);
  }

  // 如果存在某个点无法到达,则源点到该点的耗时为Integer.MAX_VALUE
  console.log(ans == Infinity ? -1 : ans);
})();

Java算法源码

import java.util.*;

public class Main {
  public static void main(String[] args) {
    Scanner sc = new Scanner(System.in);

    int n = sc.nextInt();

    // 邻接表
    HashMap<Integer, ArrayList<int[]>> graph = new HashMap<>();

    int m = sc.nextInt();
    for (int i = 0; i < m; i++) {
      int u = sc.nextInt(); // 出发点
      int v = sc.nextInt(); // 目标点
      int w = sc.nextInt(); // 出发点到达目标点的耗时

      graph.putIfAbsent(u, new ArrayList<>());
      graph.get(u).add(new int[] {v, w});
    }

    // 记录源点到其他剩余的最短耗时
    int[] dist = new int[n + 1];
    // 初始时,假设源点不可达其他剩余点,即源点到达其他点的耗时无限大
    Arrays.fill(dist, Integer.MAX_VALUE);

    // 源点
    int src = sc.nextInt();
    // 源点到达源点的耗时为0
    dist[src] = 0;

    // 优先队列needCheck中记录的其实是:已被探索过的路径的终点(路径指的是源点->终点)
    // 优先队列优先级规则是,路径终点的权重(即源点->终点的耗时)越小越优先
    PriorityQueue<Integer> needCheck = new PriorityQueue<>((a, b) -> dist[a] - dist[b]);
    // 初始被探索过的路径只有源点本身
    needCheck.add(src);

    // 记录对应点是否在needCheck中
    boolean[] visited = new boolean[n + 1];
    visited[src] = true;

    while (needCheck.size() > 0) {
      // 取出最优路径的终点(耗时最少的路径)作为新的起点
      int cur = needCheck.poll();
      visited[cur] = false;

      // 如果cur有可达的其他点
      if (graph.containsKey(cur)) {
        for (int[] next : graph.get(cur)) {
          // v是可达的其他店
          // w是cur->v的耗时
          int v = next[0], w = next[1];

          // 那么如果从源点到cur点的耗时是dist[cur],那么源点到v点的耗时就是dist[cur] + w
          int newDist = dist[cur] + w;
          // 而源点到v的耗时之前是dist[v],因此如果newDist < dist[v],则找到更少耗时的路径
          if (dist[v] > newDist) {
            // 更新源点到v的路径,即更新v点权重
            dist[v] = newDist;
            // 如果v点不在needCheck中,则加入,因为v作为终点的路径需要加入到下一次最优路径的评比中
            if (!visited[v]) {
              visited[v] = true;
              needCheck.add(v);
            }
          }
        }
      }
    }

    // dist记录的是源点到达其他各点的最短耗时,我们取出其中最大的就是源点走完所有点的最短耗时
    int ans = 0;
    for (int i = 1; i <= n; i++) {
      ans = Math.max(ans, dist[i]);
    }

    // 如果存在某个点无法到达,则源点到该点的耗时为Integer.MAX_VALUE
    System.out.println(ans == Integer.MAX_VALUE ? -1 : ans);
  }
}

Python算法源码

import sys

# 输入获取
n = int(input())

# 邻接表
graph = {}

m = int(input())
for i in range(m):
    # 出发点, 目标点, 出发点到达目标点的耗时
    u, v, w = map(int, input().split())
    graph.setdefault(u, [])
    graph[u].append([v, w])

# 记录源点到其他各点的最短耗时
# 初始时,假设源点不可达其他剩余点,即源点到达其他点的耗时无限大
dist = [sys.maxsize] * (n+1)

# 源点
src = int(input())
# 源点到达源点的耗时为0
dist[src] = 0

# needCheck中记录的其实是:已被探索过的路径的终点(路径指的是源点->终点)
# 排序规则是,路径终点的权重(即源点->终点的耗时)越小越靠后
# 初始被探索过的路径只有源点本身
needCheck = [src]

# 记录对应点是否在needCheck中
visited = [False] * (n+1)
visited[src] = True

while len(needCheck) > 0:
    # 取出最优路径的终点(耗时最少的路径)作为新的起点
    cur = needCheck.pop()
    visited[cur] = False

    # 如果cur有可达的其他点
    if graph.get(cur) is not None:
        # v是可达的其他店,w是cur->v的耗时
        for v, w in graph[cur]:
            # 那么如果从源点到cur点的耗时是dist[cur],那么源点到v点的耗时就是dist[cur] + w
            newDist = dist[cur] + w

            # 而源点到v的耗时之前是dist[v],因此如果newDist < dist[v],则找到更少耗时的路径
            if dist[v] > newDist:
                # 更新源点到v的路径,即更新v点权重
                dist[v] = newDist
                # 如果v点不在needCheck中,则加入,因为v作为终点的路径需要加入到下一次最优路径的评比中
                if not visited[v]:
                    visited[v] = True
                    needCheck.append(v)
                    needCheck.sort(key=lambda x: -dist[x])

ans = max(dist[1:])

print(-1 if ans == sys.maxsize else ans)

C算法源码

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

#define MAX_SIZE 200

#define MAX(a,b) ((a) > (b) ? (a) : (b))

/** 链表节点 **/
typedef struct ListNode {
    int v; // 目标点
    int w; // 出发点到达目标点的耗时
    struct ListNode *next;
} ListNode;

/** 链表 **/
typedef struct LinkedList {
    int size;
    ListNode *head;
    ListNode *tail;
} LinkedList;

/** 初始化链表 **/
LinkedList *new_LinkedList() {
    LinkedList *link = (LinkedList *) malloc(sizeof(LinkedList));
    link->head = NULL;
    link->tail = NULL;
    link->size = 0;
    return link;
}

/** 链表尾插 **/
void add_LinkedList(LinkedList *link, int v, int w) {
    ListNode *node = (ListNode *) malloc(sizeof(ListNode));
    node->v = v;
    node->w = w;
    node->next = NULL;

    if (link->size == 0) {
        link->head = node;
        link->tail = node;
    } else {
        link->tail->next = node;
        link->tail = node;
    }

    link->size++;
}

// 记录源点到其他各点的最短耗时
int dist[MAX_SIZE];

int cmp(const void* a, const void* b) {
    int A = *((int*) a);
    int B = *((int*) b);
    return dist[B] - dist[A];
}

int main() {
    int n;
    scanf("%d", &n);

    LinkedList **graph = (LinkedList **) calloc(n + 1, sizeof(LinkedList *));

    int m;
    scanf("%d", &m);

    for (int i = 0; i < m; i++) {
        // 出发点, 目标点, 出发点到达目标点的耗时
        int u, v, w;
        scanf("%d %d %d", &u, &v, &w);

        if (graph[u] == NULL) {
            graph[u] = new_LinkedList();
        }

        add_LinkedList(graph[u], v, w);
    }

    // 初始时,假设源点不可达其他剩余点,即源点到达其他点的耗时无限大
    for (int i = 1; i <= n; i++) {
        dist[i] = INT_MAX;
    }

    // 源点
    int src;
    scanf("%d", &src);

    // 源点到达源点的耗时为0
    dist[src] = 0;

    // needCheck中记录的其实是:已被探索过的路径的终点(路径指的是源点->终点)
    // 排序规则是,路径终点的权重(即源点->终点的耗时)越小越靠后
    int needCheck[MAX_SIZE];
    int needCheck_size = 0;

    // 初始被探索过的路径只有源点本身
    needCheck[0] = src;
    needCheck_size++;

    // 记录对应点是否在needCheck中
    int visited[n + 1];
    for (int i = 1; i <= n; i++) {
        visited[i] = 0;
    }
    visited[src] = 1;

    while (needCheck_size > 0) {
        // 取出最优路径的终点(耗时最少的路径)作为新的起点
        int cur = needCheck[needCheck_size - 1];
        needCheck_size--;
        visited[cur] = 0;

        // 如果cur有可达的其他点
        if(graph[cur] != NULL) {
            ListNode* node = graph[cur]->head;
            while(node != NULL) {
                int v = node->v; // v是可达的其他店
                int w = node->w; // w是cur->v的耗时

                // 那么如果从源点到cur点的耗时是dist[cur],那么源点到v点的耗时就是dist[cur] + w
                int newDist = dist[cur] + w;

                // 而源点到v的耗时之前是dist[v],因此如果newDist < dist[v],则找到更少耗时的路径
                if(dist[v] > newDist) {
                    // 更新源点到v的路径,即更新v点权重
                    dist[v] = newDist;
                    // 如果v点不在needCheck中,则加入,因为v作为终点的路径需要加入到下一次最优路径的评比中
                    if(!visited[v]) {
                        visited[v] = 1;
                        needCheck[needCheck_size] = v;
                        needCheck_size++;
                        qsort(needCheck, needCheck_size, sizeof(int), cmp);
                    }
                }

                node = node->next;
            }
        }
    }

    int ans = 0;
    for(int i=1; i<=n; i++) {
        ans = MAX(ans, dist[i]);
    }

    printf("%dn", ans == INT_MAX ? -1 : ans);

    return 0;
}

免责声明:

1、IT资源小站为非营利性网站,全站所有资料仅供网友个人学习使用,禁止商用
2、本站所有文档、视频、书籍等资料均由网友分享,本站只负责收集不承担任何技术及版权问题
3、如本帖侵犯到任何版权问题,请立即告知本站,本站将及时予与删除下载链接并致以最深的歉意
4、本帖部分内容转载自其它媒体,但并不代表本站赞同其观点和对其真实性负责
5、一经注册为本站会员,一律视为同意网站规定,本站管理员及版主有权禁止违规用户
6、其他单位或个人使用、转载或引用本文时必须同时征得该帖子作者和IT资源小站的同意
7、IT资源小站管理员和版主有权不事先通知发贴者而删除本文

0

评论0

站点公告

没有账号?注册  忘记密码?