这题照样套模板,但是有个地方要修改。
题目意思是:求最短路径的同时还要保证这些路径的总权值最小
在两条总权值相等的路径中,经过结点最多的那个最好。你想想,如果我能从原来已有的结点上再加一条到达目标。是不是好过从上一个结点再拉一条呢。两条总权值相等,结点数相等的路径,最后一条边权值越小的越好。
总的来说,在更新最短路径的时候,只比对最后一条边即可(无论结点数谁多谁少,只看最后那条边就可以),如果最后一条边比原来的路径的最后一条边小,就更新。
代码只要在原来的dijkstra算法上改一下就好了。
直接把“edge[1] + minCost < costs[edge[0]]”的小于号改为小于等于号“edge[1] + minCost <= costs[edge[0]]”。
我这里新加一个存储到父结点的边权值,在每次更新最短路径的时候,看新的父结点的边值是否小于以前的,是就更改父结点和父结点边的权值。修改起来有点麻烦,但是这样利于后面的算总权值和(总费用)。
这题n最大10000。。。这里算法时间复杂度为O(n^2),嗯。。。所以最后只过了80%的用例,80分。后面20%用例运行超时。
python代码:
def dij(start, graph):
n = len(graph)
costs = [99999 for _ in range(n)]
parents = [-1 for _ in range(n)]
parents_costs = [99999 for _ in range(n)]
costs[start] = 0
visited = [False for _ in range(n)]
t = []
while len(t) < n:
# 每次从costs里找最短花销,把最短花销的结点加进t中
minCost = 99999999
minNode = start
for i in range(len(costs)):
if not visited[i] and costs[i] < minCost:
minNode = i
minCost = costs[i]
t.append(minNode)
visited[minNode] = True
# 找这点的邻边(子结点不在t里面)
# 如果邻边的子结点的路径花销小于原来的花销,就更新花销和父结点
for edge in graph[minNode]:
if not visited[edge[0]] and edge[1] + minCost <= costs[edge[0]]:
if edge[1] + minCost < costs[edge[0]]:
costs[edge[0]] = edge[1] + minCost
parents[edge[0]] = minNode
parents_costs[edge[0]] = edge[1]
elif edge[1] < parents_costs[edge[0]]:
parents[edge[0]] = minNode
parents_costs[edge[0]] = edge[1]
return costs, parents, parents_costs
n, m = map(int, input().split())
# 邻接表
graph = [[] for _ in range(n)]
for i in range(m):
u, v, c = map(int, input().split())
u, v = u - 1, v - 1
graph[u].append([v, c])
graph[v].append([u, c])
costs, parents, parents_costs = dij(0, graph)
print(sum(parents_costs[1:]))