这题考最短路径,最短路径的变种
套用dijkstra模板,要改变的是 更新costs那里的判断。
重点:算到达某个结点的疲劳值
用一个数组(sum_small)存对应下标结点之前经过的连续小路之和
再用一个数组(sum_big)存对应下标结点之前的大路疲劳值之和
- 如果到达一个结点经过的是大路,只要在父结点的cost基础上加这条边的疲劳值就得到这条路径的cost。 cost = costs[minNode] + weight。小于之前的cost就更新,顺便也把该结点的sum_small归零。该结点的sum_big 被赋值为该路径疲劳。
- 如果到达一个结点经过的是小路,cost = (连续小路路程加该小路路程)的乘方 + 之前的大路疲劳。小于之前的cost就更新,顺便该结点的sum_small更新为连续小路路程加该小路程。该结点sum_big被赋值为父结点的sum_big。
注意:更新sum_big和sum_small的时候要确定cost小于原来的cost才更新。
有点抽象。。。怎么说呢,经过大路的时候算cost好算,但是经过小路就难算,所以才引进两个数组sum_small和sum_big,来存储路径前面的信息。这两个数组就是用来算小路的。经过小路的时候可以把路径分为两部分,(从路径开始到最后一个大路,最后一个大路后面的连续小路)sum_big用来存前者,sum_small用来存后者。
这个得现场画图才好说[笑哭]
python代码(100)
def dij(start, graph):
n = len(graph)
costs = [999999999 for _ in range(n)]
costs[start] = 0
sum_small = [0 for _ in range(n)] # 到每个结点的小路的累计长度
sum_big = [0 for _ in range(n)] # 到每个结点的大路的累计长度
visited = [False for _ in range(n)]
t = []
while len(t) < n:
minNode = None
minCost = 999999999
for i in range(n):
if not visited[i] and costs[i] < minCost:
minCost = costs[i]
minNode = i
t += [minNode]
visited[minNode] = True
# 更新costs
for toNode, weight, type in graph[minNode]:
if not visited[toNode]:
cost = 0 # 该路径花销
if type == 0:
cost = costs[minNode] + weight
if cost < costs[toNode]:
costs[toNode] = cost
sum_small[toNode] = 0
sum_big[toNode] = cost
elif type == 1:
cost = (sum_small[minNode] + weight) ** 2 + sum_big[minNode]
if cost < costs[toNode]:
costs[toNode] = cost
sum_small[toNode] = sum_small[minNode] + weight
sum_big[toNode] = sum_big[minNode]
return costs
n, m = map(int, input().split())
graph = [[] for _ in range(n)]
for i in range(m):
# t: 0大, 1小
t, a, b, c = map(int, input().split())
a -= 1
b -= 1
graph[a] += [[b, c, t]]
graph[b] += [[a, c, t]]
print(dij(0, graph)[-1])