📅  最后修改于: 2023-12-03 15:28:43.991000             🧑  作者: Mango
本题是计算机科学门类历年考试中的一道题目,涉及图论与逻辑运算。
给定一个拓扑有序的图 $G = (V, E)$,其顶点标号为 $1, 2, …, n$,边集 $E$ 中的元素 $(u, v)$ 表示顶点 $u$ 在拓扑上在 $v$ 前面。图中有 $2$ 个特殊的顶点:起始节点 $s$ 和终止节点 $t$。钦定 $s$ 在拓扑上在 $t$ 前面。将图中顶点按其拓扑顺序编号,设起始节点 $s$ 的顶点编号为 $1$,终止节点 $t$ 的顶点编号为 $n$。在这个拓扑排序下,路径 $(s, t)$ 中第 $i$ 个顶点编号为 $p_i$,如果 $(p_i , p_{i+1}) \in E$ 则有一个门,基本门的造价为 $1$,存在一些特殊的门,他的造价为 $c$,这些门的位置在 $i_1, i_2, …, i_k$。通过找一条路径,令路径上的所有门的造价之和最小。
编写一个函数 int findCost(int n, int* cost, int s, int t, int k, int* gates)
,其中输入参数为:
输出一个整数,表示满足条件的路径的最小成本。
n = 6, cost[] = {0, 3, 4, 2, 5, 1, 8}, s = 1, t = 6, k = 2, gates[] = {3, 5}
8
有两个特殊门,分别在第 $3$ 和第 $5$ 个点,造价分别为 $2$ 和 $1$,寻找路径 $(1, 2, 3, 4, 5, 6)$,这条路径经过两个特殊点,因此总成本应该为 $2 + 1 = 3$,但是存在路径 $(1, 2, 4, 5, 6)$,总成本为 $5 + 1 = 6$,显然更优。因此输出结果为 $8$。
通过深度优先搜索或广度优先搜索遍历所有节点,并记录当前到达节点时的路径上所经过的特殊门,以及对应的成本和。然后比较不同路径的成本之和,取最小值即可。
伪代码如下:
visited = set()
path = []
min_cost = float('inf')
# 定义深度优先搜索函数
def dfs(node, total_cost, has_gate):
if node in visited:
return
if node == t:
if total_cost < min_cost:
min_cost = total_cost
return
visited.add(node)
path.append(node)
for neighbor in graph[node]:
if neighbor not in visited:
if neighbor in gates:
dfs(neighbor, total_cost + cost[gates.index(neighbor)], True)
else:
if has_gate:
dfs(neighbor, total_cost + cost[-1], True) # cost[-1] 为普通门的造价
else:
dfs(neighbor, total_cost, False)
visited.remove(node)
path.pop()
另外,我们也可以使用 Dijkstra 算法或者 Bellman-Ford 算法来解决这道题目。
对于 Dijkstra 算法,我们可以将图中不同的边权分为两种,一种是普通门,权值为 $c$,另外一种是特殊门,权值为每个特殊门所在节点的权值。在算法的过程中,我们使用一个最小堆来维护哪些节点的路径成本已经被确定,然后用一个最小堆,找到所有与这些节点相邻的节点的路径成本,更新堆中的信息即可。
对于 Bellman-Ford 算法,我们可以先将所有的节点的路径成本都设置为正无穷大,将出发点的路径成本设置为 $0$,然后依次遍历每条边,更新所有节点的路径成本。这个算法的好处是相对简单,但是效率稍低。
import heapq
def dijkstra(graph, cost, source, dest, gates):
dist = [float('inf')] * len(graph)
dist[source] = 0
q = []
heapq.heappush(q, (0, source, 0))
while q:
curr_dist, curr_node, has_gate = heapq.heappop(q)
if curr_node == dest:
return curr_dist
if dist[curr_node] < curr_dist:
continue
for neighbor in graph[curr_node]:
if neighbor in gates:
dist_cost = curr_dist + cost[gates.index(neighbor)]
heapq.heappush(q, (dist_cost, neighbor, True))
else:
dist_cost = curr_dist + cost[-1] if has_gate else curr_dist
heapq.heappush(q, (dist_cost, neighbor, False))
if dist[neighbor] > dist_cost:
dist[neighbor] = dist_cost
return -1
def findCost(n, cost, s, t, k, gates):
graph = [[] for _ in range(n)]
for i in range(n):
if i > 0:
graph[i].append(i - 1)
if i < n - 1:
graph[i].append(i + 1)
return dijkstra(graph, cost, s-1, t-1, [x-1 for x in gates] if k else [])
上面的代码实现使用了 Dijkstra 算法来解决这个问题,使用了 Python 内置的 heapq 库来实现最小堆。
本题是一道典型的图论题目,要求我们通过搜索或者更高效的图算法来寻找一条路径,使得路径中的所有特殊门成本之和最小。本题中比较容易出现的错误包括: