CCF-201609-4-交通规划

这题照样套模板,但是有个地方要修改。

题目意思是:求最短路径的同时还要保证这些路径的总权值最小
在两条总权值相等的路径中,经过结点最多的那个最好。你想想,如果我能从原来已有的结点上再加一条到达目标。是不是好过从上一个结点再拉一条呢。两条总权值相等,结点数相等的路径,最后一条边权值越小的越好。

总的来说,在更新最短路径的时候,只比对最后一条边即可(无论结点数谁多谁少,只看最后那条边就可以),如果最后一条边比原来的路径的最后一条边小,就更新。

代码只要在原来的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:]))

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值