python 使用 Dijkstra算法解决 温差最小路径 问题

14 篇文章 0 订阅

问题描述

一些村庄由许多条小路连接,由于每条小路处于不同的地理位置,因此每条小路上的温度是不一样的。村民们要前往另一村庄时,对这条路径的绝对温度没有要求,但若一条路径的最大温度与最低温度之间的温差过大,会导致感冒。
请你找出两个村庄间的温差最小的路径。

输入

  • 第一行是一个正整数q,表示测试例数量。
  • 对每个测试例
    第一行有2个整数n(1<n≤400)和m(m≤2000),表示有n个村庄和m条小路。
    接下来m行都是3个正整数,分别是小路起始村庄号,小路终止村庄号,小路上的温度T(T≤2000000)。
    然后有一个正整数P(P≤10),表示寻路次数。
    接下来P行,每行有2个正整数,分别表示村民的起始村庄号,村民的目的村庄号。

输出

每个寻路打印一行,表示温差最小的温差,若不能到达,输出-1.

输入样例

1
5 5
1 2	2
1 5	6
2 5	7
3 4	4
3 5	8
2
1 3
1 2

route

输出结果

2
0

解题思路

solution

代码实现

#!/usr/bin/env python3
#temperature.py
#fumiama 20201120

from heapq import heappop, heappush, heapify

class UnionFindSet(object):
    def __init__(self, nodes):
        self.fatherMap = {}
        self.setNumMap = {}
        for node in nodes:
            self.fatherMap[node] = node
            self.setNumMap[node] = 1
    def findFather(self, node):
        father = self.fatherMap[node]
        if (node != father):
            father = self.findFather(father)
        self.fatherMap[node] = father
        return father
    def isSameSet(self, a, b):
        return self.findFather(a) == self.findFather(b)
    def union(self, a, b):
        if a is None or b is None: return
        aFather = self.findFather(a)
        bFather = self.findFather(b)
        if (aFather != bFather):
            aNum = self.setNumMap[aFather]
            bNum = self.setNumMap[bFather]
            if (aNum <= bNum):
                self.fatherMap[aFather] = bFather
                self.setNumMap[bFather] = aNum + bNum
                self.setNumMap.pop(aFather)
            else:
                self.fatherMap[bFather] = aFather
                self.setNumMap[aFather] = aNum + bNum
                self.setNumMap.pop(bFather)

class Node(object):
    def __init__(self, name):
        self.name = name
        self.distance = 0
        self.path = [name]
        self.maxT = -1
        self.minT = 2000001
    def __repr__(self):
        return "号节点" + ", 最短路径花费"+ str(self.distance)+ ": " + str(self.path) + '\n'
    def setNode(self, preNode, tempDiff):
        self.distance = tempDiff
        self.path = preNode.path[:]
        self.path.append(self.name)
    def getNewTempDiff(self, temp):
        minT = self.minT
        maxT = self.maxT
        return (temp if temp > maxT else maxT) - (temp if temp < minT else minT)
    def setStartTemp(self, temp): self.maxT = self.minT = temp

class Graph(object):
    def __init__(self, nodeCnt):
        self.nodes = dict()
        self.node2edge = dict()
        self._node2edge = dict()
        self.nodeNames = set()
        self.nodeCnt = nodeCnt
    def __repr__(self):
        return "图共有" + str(self.nodeCnt) + "个节点如下:\n " + str(self.nodes)
    def addEdge(self, start, end, weight):      #无向图
        self._addEdge(start, end, weight)
        self._addEdge(end, start, weight)
    def _addEdge(self, start, end, weight):     #有向图
        if start not in self.nodes.keys(): self.nodes[start] = Node(start)
        newEdge = (weight, end)
        if start not in self.node2edge.keys():
            self.node2edge[start] = {newEdge}
            self._node2edge[start] = {newEdge}
        else:
            self.node2edge[start].add(newEdge)
            self._node2edge[start].add(newEdge)
        if start not in self.nodeNames: self.nodeNames.add(start)
        if end not in self.nodeNames: self.nodeNames.add(end)
    def resetNode2Edge(self): self.node2edge = self._node2edge.copy()
    def getMinTempDiff(self, start, end):
        wedge = []
        for e in self.node2edge[start]:
            wedge.append((0, start, e[1]))
            self.nodes[e[1]].setStartTemp(e[0])
            self.node2edge[e[1]].remove((e[0], start))
        self.node2edge[start] = set()
        forest = UnionFindSet(self.nodeNames)
        result = -1
        while wedge:
            #print("带权边界边:", wedge)
            minEdge = heappop(wedge)
            thisNode = self.nodes[minEdge[1]]
            nextNode = self.nodes[minEdge[2]]
            if not forest.isSameSet(thisNode.name, nextNode.name):
                nextNode.setNode(thisNode, minEdge[0])
                if nextNode.name == end:
                    result = nextNode.distance
                    break
                edgesOfNextNode = self.node2edge[nextNode.name]
                while edgesOfNextNode:
                    edge = edgesOfNextNode.pop()
                    self.node2edge[edge[1]].remove((edge[0], nextNode.name))
                    heappush(wedge, (nextNode.getNewTempDiff(edge[0]), nextNode.name, edge[1]))
                forest.union(thisNode.name, nextNode.name)
        return result

if __name__ == '__main__':
    q = int(input())
    while q:
        n, m = map(int, input().split())
        g = Graph(n)
        while m:
            a, b, t = map(int, input().split())
            g.addEdge(a, b, t)
            m -= 1
        p = int(input())
        while p:
            a, b = map(int, input().split())
            print(g.getMinTempDiff(a, b))
            g.resetNode2Edge()
            p -= 1
        q -= 1
  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值