python实现Bellman-Ford、Dijkstra算法--最小费用最大流问题
Bellman-Ford、Dijkstra算法--最小费用最大流问题
引言
贝尔曼-福特算法 (Bellman–Ford algorithm)用于计算出起点到各个节点的最短距离,支持存在负权重的情况 它的原理是对图进行最多V-1次松弛操作,得到所有可能的最短路径。
迪杰斯特拉(Dijkstra)算法是典型最短路径算法,用于计算一个节点到其他节点的最短路径。 它的主要特点是以起始点为中心向外层层扩展(广度优先搜索思想),直到扩展到终点为止。 基本思想通过Dijkstra计算图G中的最短路径时,需要指定起点s(即从顶点s开始计算)。
目录
问题描述
最小费用最大流问题
最小费用最大流问题是经济学和管理学中的一类典型问题。在一个网络中每段路径都有"容量"和"费用"两个限制条件下,此类问题的研究试图寻找出:流量从A到B,如何选择路径、分配经过路径的流量,可以达到所用的费用最小的要求。
最小费用最大流建立在最大流和网络流问题的基础之上。
算法思想
1、把各条弧上单位流量的费用看成某种长度,用Dijkstra求最短路的方法确定一条自Vs至Vt的最短路。
2、再将这条最短路作为可扩充路(增广链),用求解最大流问题的方法将其上的流量增至最大可能值。
3、调整增广链上前向边和后向边的流量。(当增广链上前向边为饱和边时,寻找下一条增广链,可以看做把该饱和边刨去)
4、如此重复第1、2、3步,直到找不到可扩充路(增广链),最终得到最小费用最大流。
实现过程
(1)用Dijkstra求最短路的方法确定一条自Vs至Vt的最短路。
(2)再将这条最短路作为可扩充路(增广链),用求解最大流问题的方法将其上的流量增至最大可能值。
由图像可知流量增至最大可能值为:2。
(3)调整增广链上前向边和后向边的流量。
(4)用Dijkstra求最短路的方法确定一条自Vs至Vt的最短路。
(5)再将这条最短路作为可扩充路(增广链),用求解最大流问题的方法将其上的流量增至最大可能值。
由图像可知流量增至最大可能值为:8。
(6)调整增广链上前向边和后向边的流量。
(7)用Dijkstra求最短路的方法确定一条自Vs至Vt的最短路。
(8)再将这条最短路作为可扩充路(增广链),用求解最大流问题的方法将其上的流量增至最大可能值。
由图像可知流量增至最大可能值为:6。
(9)调整增广链上前向边和后向边的流量。
(10)用Dijkstra求最短路的方法确定一条自Vs至Vt的最短路。
(11)再将这条最短路作为可扩充路(增广链),用求解最大流问题的方法将其上的流量增至最大可能值。
由图像可知流量增至最大可能值为:8。
(12)调整增广链上前向边和后向边的流量。
(13)用Dijkstra求最短路的方法确定一条自Vs至Vt的最短路。
(14)再将这条最短路作为可扩充路(增广链),用求解最大流问题的方法将其上的流量增至最大可能值。
由图像可知流量增至最大可能值为:18。
(15)调整增广链上前向边和后向边的流量。
(16)用Dijkstra求最短路的方法无法确定一条自Vs至Vt的最短路。
(17)最终得到最小费用最大流。
最大流为:各条边的流量与对应边的费用积的总和=1344。
代码实现
python实现如下
class Graph:
def __init__(self,num):
self.data_li = [['inf' for i in range(num)] for j in range(num)] #创建一个记录每个点到其余个点的路径长度的表,开始时全为inf
self.mark = [] #用于记录已经标记过的点
self.distance = ['inf' for i in range(num)] #记录目前起始点到其余个的最短距离
self.path = ['inf' for i in range(num)]
self.data_f_li = [[('inf',0) for i in range(num)] for i in range(num)]
self.expand_li = [['inf' for i in range(num)] for j in range(num)] #创建一个记录每个点到其余个点的路径长度的表,开始时全为inf
def add_edge(self,data,data_f): #记录各点到可到达的其余点的路径长度
for i in data:
self.data_li[i[0]][i[1]] = i[2]
self.expand_li[i[0]][i[1]] = i[2]
for i in data_f:
self.data_f_li[i[0]][i[1]] = (i[2],0)
def dijkstra(self,start,num):
self.mark = [] # 用于记录已经标记过的点
self.distance = ['inf' for i in range(num)] # 记录目前起始点到其余个的最短距离
self.path = ['inf' for i in range(num)]
self.mark.append(start)
self.distance[start] = 0
que = []
que.append(start)
while que:
curnode = que.pop(0)
for i in range(len(self.data_li[curnode])):
if i not in self.mark:
if self.distance[i] == 'inf':
if self.data_li[curnode][i] == 'inf':
continue
else:
self.distance[i] = self.distance[curnode] + self.data_li[curnode][i]
self.path[i] = curnode
continue
if self.data_li[curnode][i] == 'inf':
continue
else:
if self.distance[curnode] + self.data_li[curnode][i] < self.distance[i]:
self.distance[i] = self.distance[curnode] + self.data_li[curnode][i]
self.path[i] = curnode
cur_min_val = [self.distance[i] for i in range(len(self.distance)) if i not in self.mark and self.distance[i] != 'inf']
if cur_min_val:
cur_min_val = min(cur_min_val)
for i in range(len(self.distance)):
if i not in self.mark:
if self.distance[i] == cur_min_val:
self.mark.append(i)
que.append(i)
if self.path[-1] == 'inf':
return
li = []
li.append(len(self.path)-1)
a = len(self.path)-1
while a:
if self.path[a] == 'inf':
break
else:
li.insert(0,self.path[a])
a = self.path[a]
return li
def bellman_ford(self,start,num):
information = self.dijkstra(start,num)
while information:
min_val = min([self.data_f_li[information[i]][information[i+1]][0] - self.data_f_li[information[i]][information[i+1]][1] for i in range(len(information)-1)])
for i in range(len(information)-1):
self.data_f_li[information[i]][information[i+1]] = (self.data_f_li[information[i]][information[i+1]][0],self.data_f_li[information[i]][information[i+1]][1] + min_val)
for i in range(len(information)-1):
if self.data_f_li[information[i]][information[i+1]][0] == self.data_f_li[information[i]][information[i+1]][1]:
self.data_li[information[i]][information[i+1]] = 'inf'
information = self.dijkstra(start,num)
expand = 0
for i in range(len(self.data_f_li)):
for j in range(len(self.data_f_li[0])):
if self.data_f_li[i][j][1] != 0:
expand += self.data_f_li[i][j][1] * self.expand_li[i][j]
return expand
if __name__ == '__main__':
data = [(0,1,8),(0,2,10),(0,3,15),(1,4,9),(1,5,11),(2,5,8),(2,6,6),(3,6,14),(4,7,8),(5,7,9),(6,7,10)]
data_f = [(0,1,15),(0,2,10),(0,3,20),(1,4,7),(1,5,10),(2,5,8),(2,6,2),(3,6,18),(4,7,6),(5,7,16),(6,7,20)]
d = Graph(8)
d.add_edge(data,data_f)
print(d.bellman_ford(0,8))
更多推荐
所有评论(0)