📅  最后修改于: 2023-12-03 15:42:22.747000             🧑  作者: Mango
有一个有向图,每个点上有一个权值,从起点开始,每次可以从当前点出发到任意一条出边的终点,并累加上终点的权值。注意,每个点只能经过一次,现在要求出从起点到终点的路径中,所有路径点权和最大的路径。
第 1 行有两个整数,N,M,分别表示点的个数和边的个数$(1\le N\le 10000,1\le M\le 100000)$。
第 2 行有 N 个整数,表示每个点的点权。
接下来 M 行,每行三个整数,u,v,w(1≤u,v≤n,0≤w≤10000),表示 u 到 v 有 一条边,边权为 w。
一个整数,表示从起点到终点的路径中,所有路径点权和最大的路径的点权和。
5 5
1 2 3 4 5
1 2 1
1 4 4
4 5 5
2 5 2
5 3 1
14
本题可以借鉴一下最短路算法的思想,借助Dijkstra算法来解决最大路径问题。当然,这个最短路算法的思想要有所变更。由于Dijkstra算法中是维护的源点到各个点的最短路径,而本题需要维护源点到各个点的最大路径,因此要将贪心策略的判断条件做一些改变。我们维护一个数组 $dis$,表示从源点到各个点的最大路径,初始化为 $-\infty$。同时,我们定义一个堆 $heap$,每次将离源点最近的点加入堆中,并遍历该点所有出边,更新 $dis$ 数组中的值。注意每个点只能经过一次,因此要在更新 $dis[ v ]$ 的同时判断是否需要把 $v$ 加入堆中。另外,由于 $dis[ v ]$ 表示的是从源点到 $v$ 的最大路径,所以更新时要取 $dis[ u ]+w$ 和 $dis[ v ]$ 的最大值。
具体实现可以借用一个堆优化的Dijkstra的模板。
import heapq
# 堆优化Dijkstra算法
def dijkstra(N: int, graph: list, start: int, end: int) -> int:
# 用于标记每个节点是否被访问
visited = [False] * N
# 源点到各个点的最大路径
dis = [-float("inf")] * N
# 将源点到自身的路径赋值为0(源点到自己的最大路径为0)
dis[ start ] = 0
# 堆优化Dijkstra算法的核心:堆
heap = [(0, start)]
while heap:
cur_dis, cur = heapq.heappop(heap)
if visited[ cur ]:
continue
# 更新距离
visited[ cur ] = True
for to, w in graph[ cur ]:
if not visited[ to ] and dis[ to ] < cur_dis+w:
dis[ to ] = cur_dis+w
heapq.heappush(heap, (dis[ to ], to))
return dis[ end ]
# 主函数
if __name__ == "__main__":
# 读入数据
N, M = map(int, input().split())
cost = list(map(int, input().split()))
graph = [[] for _ in range(N)]
for _ in range(M):
u, v, w = map(int, input().split())
graph[ u-1 ].append((v-1, w))
# 执行Dijkstra算法
print(dijkstra(N, graph, 0, N-1) + cost[0])
代码中采用了 $graph$ 数组来存储有向图的信息,其每个元素是一个列表,列表中存储了出边的终点和边权。在优化Dijkstra算法时,堆中存储的是一个二元组 $(dis[ i ], i)$,表示从源点到 $i$ 的最大路径长度和节点编号。对于每个节点 $v$,我们首先判断它是否被访问过。如果没有,则计算从源点到 $v$ 的最大路径长度,并将其加入堆中。如果已经被访问过,则忽略。以此类推,直到堆为空。在代码中,我们将节点编号从 $0\sim N-1$ 编号,需要时注意索引问题。最后输出的答案需要加上源点的点权。