【算法——Python实现】有负权图求单源最短路径BellmanFord算法
2017-10-20 17:06
239 查看
class Edge(object): """边""" def __init__(self, a, b, weight): self.a = a # 第一个顶点 self.b = b # 第二个顶点 self.weight = weight # 权值 def v(self): return self.a def w(self): return self.b def wt(self): return self.weight def other(self, x): # 返回x顶点连接的另一个顶点 if x == self.a or x == self.b: if x == self.a: return self.b else: return self.a def __lt__(self, other): # 小于号重载 return self.weight < other.wt() def __le__(self, other): # 小于等于号重载 return self.weight <= other.wt() def __gt__(self, other): # 大于号重载 return self.weight > other.wt() def __ge__(self, other): # 大于等于号重载 return self.weight >= other.wt() def __eq__(self, other): # ==号重载 return self.weight == other.wt() class DenseGraph(object): """有权稠密图 - 邻接矩阵""" def __init__(self, n, directed): self.n = n # 图中的点数 self.m = 0 # 图中的边数 self.directed = directed # bool值,表示是否为有向图 self.g = [[None for _ in range(n)] for _ in range(n)] # 矩阵初始化都为None的二维矩阵 def V(self): # 返回图中点数 return self.n def E(self): # 返回图中边数 return self.m def addEdge(self, v, w, weight): # v和w中增加一条边,v和w都是[0,n-1]区间 if v >= 0 and v < n and w >= 0 and w < n: if self.hasEdge(v, w): self.m -= 1 self.g[v][w] = Edge(v, w, weight) if not self.directed: self.g[w][v] = Edge(w, v, weight) self.m += 1 def hasEdge(self, v, w): # v和w之间是否有边,v和w都是[0,n-1]区间 if v >= 0 and v < n and w >= 0 and w < n: return self.g[v][w] != None class adjIterator(object): """相邻节点迭代器""" def __init__(self, graph, v): self.G = graph # 需要遍历的图 self.v = v # 遍历v节点相邻的边 self.index = 0 # 遍历的索引 def __iter__(self): return self def next(self): while self.index < self.G.V(): # 当索引小于节点数量时遍历,否则为遍历完成,停止迭代 if self.G.g[self.v][self.index]: r = self.G.g[self.v][self.index] self.index += 1 return r self.index += 1 raise StopIteration() class SparseGraph(object): """有权稀疏图- 邻接表""" def __init__(self, n, directed): self.n = n # 图中的点数 self.m = 0 # 图中的边数 self.directed = directed # bool值,表示是否为有向图 self.g = [[] for _ in range(n)] # 矩阵初始化都为空的二维矩阵 def V(self): # 返回图中点数 return self.n def E(self): # 返回图中边数 return self.m def addEdge(self, v, w, weight): # v和w中增加一条边,v和w都是[0,n-1]区间 if v >= 0 and v < n and w >= 0 and w < n: # 考虑到平行边会让时间复杂度变为最差为O(n) # if self.hasEdge(v, w): # return None self.g[v].append(Edge(v, w, weight)) if v != w and not self.directed: self.g[w].append(Edge(w, v, weight)) self.m += 1 def hasEdge(self, v, w): # v和w之间是否有边,v和w都是[0,n-1]区间 # 时间复杂度最差为O(n) if v >= 0 and v < n and w >= 0 and w < n: for i in self.g[v]: if i.other(v) == w: return True return False class adjIterator(object): """相邻节点迭代器""" def __init__(self, graph, v): self.G = graph # 需要遍历的图 self.v = v # 遍历v节点相邻的边 self.index = 0 # 遍历的索引 def __iter__(self): return self def next(self): if len(self.G.g[self.v]): # v有相邻节点才遍历 if self.index < len(self.G.g[self.v]): r = self.G.g[self.v][self.index] self.index += 1 return r else: raise StopIteration() else: raise StopIteration() class ReadGraph(object): """读取文件中的图""" def __init__(self, graph, filename): with open(filename, 'r') as f: line = f.readline() line = line.strip('\n') line = line.split() v = int(line[0]) e = int(line[1]) if v == graph.V(): lines = f.readlines() for i in lines: a, b, w = self.stringstream(i) if a >= 0 and a < v and b >=0 and b < v: g be0b raph.addEdge(a, b, w) def stringstream(self, text): result = text.strip('\n') result = result.split() a, b, w = result return int(a), int(b), int(w) class BellmanFord(object): """BellmanFord求单源最短路径,可以有负权值。多次执行松弛操作,一点到一点最短路径最多有V-1条边V个顶点,松弛时超过这个数则证明有负权环,无最短路径 只能处理有向图,无向图如果两个点之间权值都为负会直接形成负权环""" def __init__(self, graph, s): self.G = graph # 图 self.s = s # 原点s self.distTo = [0 for _ in range(self.G.V())] # 从原点到每个节点的权值,初始都为0 self.fromed = [None for _ in range(self.G.V())] # 记录此节点来自哪个节点的连接,存储边。None表示未被访问过 self.hasNegativeCircle = False # 是否有负权环 # BellmanFord # 共对所有顶点做V-1次松弛 for p in range(self.G.V()-1): # 每一轮松弛要对所有节点都做松弛操作 for i in range(self.G.V()): # 只对原点s或者其他已经到达的顶点做松弛操作 if self.fromed[i] or self.s == i: adj = self.G.adjIterator(self.G, i) for e in adj: # 如果w还未被访问过,或经过v的最短路径再到w节点的权值小于w之前被访问时记录的路径,则用经过v再到w的路径替代 if not self.fromed[e.w()] or self.distTo[i] + e.wt() < self.distTo[e.w()]: self.distTo[e.w()] = self.distTo[i] + e.wt() self.fromed[e.w()] = e self.hasNegativeCircle = self.detectNegativeCircle() def detectNegativeCircle(self): # 再做一轮对所有顶点的松弛操作,如果还能松弛则表示有负权环 for i in range(self.G.V()): # 只对原点s或者其他已经到达的顶点做松弛操作 if self.fromed[i] or self.s == i: adj = self.G.adjIterator(self.G, i) for e in adj: # 如果w还未被访问过,或经过v的最短路径再到w节点的权值小于w之前被访问时记录的路径,则表示一定有负权环 if not self.fromed[e.w()] or self.distTo[i] + e.wt() < self.distTo[e.w()]: return True return False def negativeCycle(self): # 查询是否有负权环 return self.hasNegativeCircle def shortestPathTo(self, w): # 从原点到w节点的权值 if not self.hasNegativeCycle and w >= 0 and w < self.G.V(): return self.distTo[w] else: return None def hasPathTo(self, w): # 从原点到w是否有路径 if w >= 0 and w < self.G.V(): return self.fromed[w] != None def shortestPath(self, w): # 从原点到w的最短路径 if not self.hasNegativeCycle and w >= 0 and w < self.G.V(): s = [] e = self.fromed[w] while e: s.append(e) e = self.fromed[e.v()] s.reverse() return s else: return None def showPath(self, w): # 输出路径 if not self.hasNegativeCycle and w >= 0 and w < self.G.V(): s = self.shortestPath(w) i = 0 while i < len(s): print s[i].v() if i == len(s) - 1: print s[i].w() i += 1
相关文章推荐
- 基于Levenberg-Marquardt训练算法的BP网络Python实现
- 常用算法之:冒泡排序(bubble)的python实现
- Python实现二分法算法实例
- 【算法导论】八皇后问题的算法实现(C、MATLAB、Python版)
- PyCon 2011 - Hidden Treasures of the Python Standard Library - 模拟hmac摘要算法的实现
- 《机器学习实战》——k-近邻算法Python实现问题记录(转载)
- 二次指数平滑算法Python实现
- Python 实现神经网络逆向传播算法(含详细注释)
- 有关在某个数组中查找一个值的算法(Python实现)
- Logistic Regression 逻辑回归算法例子,python代码实现
- 朴素贝叶斯分类算法python实现
- 局部离群点检测——LOF算法的Python实现
- 各种算法的Python实现方案
- python 实现 knn分类算法 (Iris 数据集)
- 机器学习—— 基于朴素贝叶斯分类算法构建文本分类器的Python实现
- Python实现字符串的逆序 C++字符串逆序算法
- EM 算法的 Python 实现
- Python实现的朴素贝叶斯算法经典示例【测试可用】
- 普林斯顿大学算法公开课 Python实现 (1)
- 决策树ID3 算法python实现