python实现Dijkstra算法的堆加速

本文将记录python编程实现迪杰斯塔拉算法的堆加速的相关内容
迪杰斯塔拉算法是一个动态规划算法,目的是在正权重的又向图中到一个从点A到点B的最短路径(如果有的话)。具体的算法内容在python脚本中。

'''
该python脚本为迪杰斯塔拉算法的堆加速python实现,利用堆加速可以将时间复杂度降低到mlogn
利用Dijkstra可以在一个正权重的有向图中找到从一个开始节点到可以到达的所有节点的最短距离。
该有向图共有N个顶点,顶点的索引是0、1、2、N-1。权重都是整数。在图中共有M条辺。
具体使用的命令行为 python Dijkstra.py  outputfile
inputfile:共有M+1行,每个数字都是正整数用空格隔开
	第一行:定点数、边数、开始节点
	其他行 图上一条边的开始节点索引、图上一条边的结束节点索引、该边的权重
outputfile:每一行为从开始节点到能到达的所有节点的相关内容,每个数字都是正整数并用空格隔开
	节点索引、从开始节点到该节点的最短路径、从开始节点到该节点的路径树上的父节点索引
'''
import fileinput
from heapq import *
import heapq
import sys
line_index = 0
for line in fileinput.input():
    if line_index == 0:
        node_num,edge_num,start = int(line.split(' ')[0]),int(line.split(' ')[1]),int(line.split(' ')[2])
        edge = [[sys.maxsize for j in range(node_num)] for i in range(node_num)] # 链接矩阵
        # 每一行是以该行节点为头,每一列是以该列为尾
    else:
        starting,ending,weight = int(line.split(' ')[0]),int(line.split(' ')[1]),int(line.split(' ')[2])
        edge[starting][ending] = weight    
    line_index +=1
# print(node_num,edge_num,start)
parent = [start]*node_num  # 每个节点的父节点
visit = [False]*node_num  # 每个节点是否被访问过
visit[start] = True    
pre_node_index = start
only_distacne = edge[start]


distance = [[only_distacne[i],i]  for i in range(len(only_distacne))]
heapify(distance)
while len(distance) > 0:
    min_distance,min_distance_node_index=heapq.heappop(distance)
    visit[min_distance_node_index] = True
    for i in range(node_num):
        if visit[i] :continue      
        temp = min_distance+edge[min_distance_node_index][i]
        if only_distacne[i]>temp:
            only_distacne[i] = temp
            parent[i] = min_distance_node_index
            distance.append([only_distacne[i],i])
    heapify(distance)

for i in range(len(only_distacne)):
    if only_distacne[i] != sys.maxsize:
        print(i,only_distacne[i],parent[i]) 

下面提供1个有向图的inputfile测试用例

16 28 12
12 1 2
12 3 19
7 1 20
5 6 2
8 15 19
1 6 12
8 10 12
7 3 15
4 6 11
15 14 4
12 10 9
4 0 18
0 9 12
1 2 13
11 2 11
6 9 1
6 3 6
2 4 17
5 14 16
7 4 9
0 11 20
9 0 11
13 9 12
11 9 19
14 3 11
10 7 6
3 8 5
13 5 13

下面提供下利用迪杰斯塔拉算法得到了从一个节点到图上可以到达的所有节点的数据后来测试你写的代码是否准确的脚步

#该脚本用来测试刚才写的代码是否准确,其中inputfile和outputfile的格式在上一个脚本注释中有提到
import sys

"""
Call this program from a command line as

python3 check_Dijkstra_output input_file output_file [endpoint] [> path_file]

Reads the input and output to Dijkstra's algorithm.
First checks whether every vertex's parent is a valid parent.
With an optional given endpoint (index of a vertex), it finds a path backwards to the start,
and writes it to the standard output (which you can redirect to a file via > if you want).
Writes an error message to the console if something invalid is found.
"""

infinity = float('inf')

def main():
	input_stream_1 = sys.argv[1]
	input_stream_2 = sys.argv[2]
	output_stream = sys.stdout

	adj_list = []
	s = 0
	with open(input_stream_1) as f:
		adj_list, s = read_input(f)
	n = len(adj_list)
	
	edge_lengths = {}
	for u in range(n):
		for (v,l) in adj_list[u]:
			edge_lengths[(u,v)] = l
	
	d = n*[infinity]
	parent = n*[None]

	with open(input_stream_2) as f:
		d, parent = read_output(n, f)
	d[s] = 0 # Must be here since the above line overwrites it.

	for v in range(n):
		if d[v] < infinity:
			u = parent[v]
			if None == u:
				if s == v:
					continue
				else:
					sys.stderr.write("{} has no parent.\n".format(v))
					return
			l = edge_lengths[(u,v)]
			if not d[u] + l == d[v]:
				sys.stderr.write("Mismatch between {} and its parent.\n".format(v))
				sys.stderr.write("d[{}] = {}, d[{}] = {}, l = {}\n".format(v,d[v],u,d[u],l))
				return

	if len(sys.argv) < 4:
		return
	t = int(sys.argv[3])
	path = find_path(parent,s,t)
	
	for v in path:
		output_stream.write("{}\n".format(v))
		

def read_input(input_stream):
	# Returns the adjacency list.
	lines = input_stream.read().splitlines()
	n, m, s = [int(i) for i in lines[0].split()]
	edges = [[int(x) for x in line.split()] for line in lines[1:]]
	adj_list = [[] for foo in range(n)]
	for (u,v,l) in edges:
		adj_list[u].append((v, l))
	return adj_list, s


def read_output(n, input_stream):
	# n is the number of vertices, s is the start point.
	# Returns the arrays d, parent
	d = n*[infinity]
	parent = n*[None]
	lines = input_stream.read().splitlines()
	for line in lines:
		v, d1, p = [int(x) for x in line.split()]
		d[v] = d1
		parent[v] = p
	return d, parent


def find_path(parent,s,t):
	# Find the path to the destination t using the parent array.
	path = []
	
	u = parent[t]
	if None == u and s != t:
		sys.stderr.write("{} is unreachable.\n".format(t))
	v = t
	while None != v:
		path.append(v)
		v = parent[v]
		
	return path
	

if "__main__" == __name__:
	main()

你可能感兴趣的:(python代码)