总结:

方法1: 引入path数组, 记录下每个节点 想要走最短路径到达终点的下一跳节点;

方法2: 从起点开始遍历, 遍历邻接节点, 如果当前节点到下一节点的距离+下一个节点到终点的距离=当前节点到终点的距离, 则认为该下一节点是最优路径上的节点

一般情况下, Dijkstra算法是解决单源最短路径问题的, 也就是在已知终点时, 求出图中的每个点到终点的最短距离, 但是一般只记录距离值, 不会记录具体的路径, 即怎么走能从起点通过最短路径来到达终点;

思路就是引入一个path表, 其中path[x]表示, 如果从x节点要到达终点的最短路径, 在x节点下一步应该怎么走, 获得这个path表之后, 我们只需要从起点回溯这个path表, 直到终点位置, 这样就能找到从起点到终点的最短路径了; 类似于下面这样的操作:

nodes = []
	u = nf
	while u!=nt:
		nodes.append(u)
		u = path[u]
	nodes.append(nt)

先放一段普通的Dijkstra算法的python实现

def generateDisArray(nf, nt, INF=float("inf")):
	dis = dict((k.getID(),INF) for k in net.getNodes())
	heap = []
	# u is the next node to be relaxed
	u = nf
	dis[u] = 0
	heapq.heappush(heap, [0, u])
	
	while len(heap)>0:
		p = heapq.heappop(heap)
		pid = p[1]
		pdis = p[0]
		if dis[pid] < pdis :
			continue
		for x in AdjacencyList[pid]:
			if dis[x] > dis[pid]+AdjacencyList[pid][x]:
				dis[x] = dis[pid]+AdjacencyList[pid][x]
#				这里的if判断是为了处理一些没有出度的点, 这些点不可能作为中间节点来松弛
				if AdjacencyList.__contains__(x)==True:
					heapq.heappush(heap, [dis[x], x])
		if pid==nt:
			print("Good Luck!!!!")
			return dis
	return dis;

这里我加了一个小剪枝, 因为我其实只希望找从节点nf到节点nt的最短路径, 所以我第一次对nf节点做松弛操作的时候, 其实已经可以确定此时已经找到了到nf到nt的最短路了, 后面的循环都不需要了;

然后上改进之后的Dijkstra算法:

def generateDisArray(nf, nt, INF=float("inf")):

	dis = dict((k.getID(),INF) for k in net.getNodes())
	path = {}
	heap = []
	# u is the next node to be relaxed
	u = nf
	dis[u] = 0
	heapq.heappush(heap, [0, u])
	
	while len(heap)>0:
		p = heapq.heappop(heap)
		pid = p[1]
		pdis = p[0]
		if dis[pid] < pdis :
			continue
		for x in AdjacencyList[pid]:
			if dis[x] > dis[pid]+AdjacencyList[pid][x]:
				dis[x] = dis[pid]+AdjacencyList[pid][x]
				path[x] = pid
#				这里的if判断是为了处理一些没有出度的点, 这些点不可能作为中间节点来松弛
				if AdjacencyList.__contains__(x)==True:
					heapq.heappush(heap, [dis[x], x])
		if pid==nt:
			print("Good Luck!!!!")
			return dis, path
	return dis, path;

这里自己在第一次写的时候犯了一个错误, 当时想当然的认为, 求出dis数组之后, 只要从起点开始, 贪心的去找邻接的点中dis值小的节点, 直到找到终点位置, 但是其实这个想法是错误的, 因为这样贪心的策略其实只考虑到了下一步的利益, 当前一步的消耗是没有考虑的

想到这里, 我考虑到, 那如果把当前的消耗考虑进去是不是就可以了呢? 应该是可以的, 寻找最优路径的实现如下

dis = generateDisArray(nf, nt)
	edges = []
	u = net.getNode(nt)
	while u.getID()!=nf:
		for e in u.getIncoming():
			if e.allows(newVehicletype)==False:
				continue;
#这里的意思就是从当前节点到下一节点的消耗, 加上下一节点的dis值如果等于当前节点的dis值
#那么就认为走这个节点是最优的路径
			if e.getLanes()[0].getLength()+dis[e.getFromNode().getID()]==dis[u.getID()]:
				edges.append(str(e.getID()))
				u = e.getFromNode()
				break