我们有一系列公交路线。每一条路线 routes[i] 上都有一辆公交车在上面循环行驶。例如,有一条路线 routes[0] = [1, 5, 7],表示第一辆 (下标为 0) 公交车会一直按照 1->5->7->1->5->7->1->... 的车站路线行驶。
假设我们从 S 车站开始(初始时不在公交车上),要去往 T 站。 期间仅可乘坐公交车,求出最少乘坐的公交车数量。返回 -1 表示不可能到达终点车站。
示例:
输入: routes = [[1, 2, 7], [3, 6, 7]] S = 1 T = 6 输出:2 解释: 最优策略是先乘坐第一辆公交车到达车站 7, 然后换乘第二辆公交车到车站 6。
提示:
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/bus-routes
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
使用邻接表表示法构造图,关于图和图的邻接表表示法请参考:http://timd.cn/data-structure/graph/
使用分支限界算法解题。关于分支限界算法请参考:http://timd.cn/data-structure/branch-and-bound/
本题中使用的剪枝函数是:
当达到某一车站时,首先计算通过乘坐哪些车到达的该车站,以及换乘次数,然后执行下面的流程:
class Solution(object):
class Graph(object):
class HeadNode(object):
def __init__(self, station_no, next_node=None):
self.station_no = station_no
self.next_node = next_node
class AdjacentNode(object):
def __init__(self, station_no, next_node=None):
self.station_no = station_no
self.next_node = next_node
self.bus_nos = set()
def __init__(self):
self._heads = {}
def add_edge(self, from_station_no, to_station_no, bus_no=None):
self._add_edge(from_station_no, to_station_no, bus_no)
self._add_edge(to_station_no, from_station_no, bus_no)
def _add_edge(self, from_station_no, to_station_no, bus_no=None):
if from_station_no not in self._heads:
self._heads[from_station_no] = self.HeadNode(from_station_no)
head = self._heads[from_station_no]
temp = head
while temp.next_node is not None:
if temp.next_node.station_no == to_station_no:
if bus_no is not None:
temp.next_node.bus_nos.add(bus_no)
return
temp = temp.next_node
if to_station_no not in self._heads:
self._heads[to_station_no] = self.HeadNode(to_station_no)
adjacent = self.AdjacentNode(to_station_no)
if bus_no is not None:
adjacent.bus_nos.add(bus_no)
temp.next_node = adjacent
def get_next_stations(self, station_no):
if station_no not in self._heads:
return
temp = self._heads[station_no]
while temp.next_node is not None:
yield temp.next_node
temp = temp.next_node
def get_vertex(self, station_no):
if station_no not in self._heads:
raise ValueError()
return self._heads[station_no]
class Node(object):
def __init__(self, reach_bus_nos, change_number):
self.reach_bus_nos = reach_bus_nos
self.change_number = change_number
def numBusesToDestination(self, routes, S, T):
"""
:type routes: List[List[int]]
:type S: int
:type T: int
:rtype: int
"""
g = self._generate_graph(routes)
reach_bus_nos = set()
for n in g.get_next_stations(S):
reach_bus_nos.update(n.bus_nos)
if not reach_bus_nos:
return -1
if S == T:
return 0
stations = {S: self.Node(reach_bus_nos, 1)}
queue = [S]
while queue:
station_no = queue.pop(0)
for next_station in g.get_next_stations(station_no):
intersection = stations[station_no].reach_bus_nos & next_station.bus_nos
arrived_bus_nos = intersection or next_station.bus_nos
change_number = stations[station_no].change_number + (not intersection)
if next_station.station_no not in stations or \
change_number < stations[next_station.station_no].change_number:
stations[next_station.station_no] = self.Node(
arrived_bus_nos,
change_number)
queue.append(next_station.station_no)
elif change_number == stations[next_station.station_no].change_number:
if not arrived_bus_nos.issubset(
stations[next_station.station_no].reach_bus_nos):
stations[next_station.station_no].reach_bus_nos.update(arrived_bus_nos)
queue.append(next_station.station_no)
if T not in stations:
return -1
return stations[T].change_number
def _generate_graph(self, routes):
g = self.Graph()
for bus_no, route in enumerate(routes, start=1):
for ind in range(len(route) - 1):
g.add_edge(route[ind], route[ind + 1], bus_no)
return g