📜  门|门CS 2011 |第 53 题(1)

📅  最后修改于: 2023-12-03 15:42:22.649000             🧑  作者: Mango

题目介绍

本题为 "门" 问题,是计算机科学经典问题之一。题目来源为 门 | 门CS 2011 的第 53 题。

该问题主要考察了图论的算法,涉及图的遍历和深度优先搜索(DFS)算法。该问题通常用于训练计算机科学和算法的竞赛和编程挑战。

题目描述

有一张 $n$ 个节点和 $m$ 条边的无向图,其中每个节点都标记有数字 $a_i$,$i \in [1, n]$。现在有如下两种操作:

  1. 选定一个节点 $i$,将 $a_i$ 的值加上 $1$。
  2. 查询从节点 $x$ 到节点 $y$ 的最短距离,其中最短距离定义为两个节点之间的最短路径上所有节点的 $a_i$ 值的乘积。

输入数据格式:第一行包含 $n$ 和 $m$,接下来 $n$ 行,每行一个整数,表示每个节点 $a_i$ 的初始值,最后 $m$ 行,每行包含两个整数 $u$ 和 $v$,表示一条无向边 $(u,v)$。

输出数据格式:每输入一个询问,输出一行一个整数,表示查询得到的最短距离。如果不能到达,则输出 -1。

数据范围:

$1 \leq n \leq 10^5$

$1 \leq m \leq 2 \times 10^5$

解题思路
算法概述

首先,我们需要知道确定一条最短路径的方法。通常,我们使用 BFS(广度优先搜索)或 Dijkstra 算法来解决这个问题。

不过,本题中的最短路径问题有一个特殊的要求,即要求路径上所有节点的 $a_i$ 的乘积值。

这启示我们对 BFS 或 Dijkstra 算法进行修改。为了强制所有路径上的节点都必须被遍历到,我们可以使用 DFS 算法来实现最短路径的搜索。

而此时,我们需要记录搜索路径上所有节点的 $a_i$ 值的乘积值。DFS 算法的搜索过程中,我们可以将当前节点的 $a_i$ 值乘到已有的乘积中,直到搜索到目标节点。这一乘积值就是最短路径的乘积值。

算法实现

我们可以采用以下步骤来实现本题:

  1. 将输入的无向图存储为一个邻接表或邻接矩阵结构,方便后续访问。
  2. 对邻接表或邻接矩阵运行深度优先搜索算法,搜索所有从起点 $s$ 开始遍历的路径,并记录已遍历节点的 $a_i$ 值乘积。
  3. 终止条件:当搜索到目标节点 $t$ 时,计算路径的 $a_i$ 值乘积并返回结果。
  4. 重复步骤 2 和 3,直到所有询问都被处理完。

需要注意的是,由于本题中起点和终点都是动态变化的,因此在运行 DFS 算法时,我们需要对每个询问都重新运行一次搜索算法,而不能预先计算出所有的最短路径。

时间复杂度

在本算法中,在最坏情况下,我们需要对每个询问重新运行一次深度优先搜索算法。因此,算法的时间复杂度是 $O(q \times (n + m))$,其中 $q$ 是查询的次数,$n$ 是节点数,$m$ 是边数。

代码实现

可以参考以下伪代码实现:

# 邻接表
graph = [[] for i in range(n+1)]
for i in range(m):
    u, v = map(int, input().split())
    graph[u].append((v, 1))
    graph[v].append((u, 1))

# 深度优先搜索
def dfs(s, t):
    visited = [False]*(n+1)
    product = 1
    stack = [(s, product)]
    
    while stack:
        node, p = stack.pop()
        if visited[node]:
            continue
        visited[node] = True
        product *= a[node]
        if node == t:
            return product
        for next_node, weight in graph[node]:
            stack.append((next_node, product*weight))
    return -1

# 查询
for i in range(q):
    s, t = map(int, input().split())
    result = dfs(s, t)
    print(result)

以上是Python实现的伪代码,具体代码实现可根据实际需要进行修改。