python实现Bellman-Ford、Dijkstra算法--最小费用最大流问题

引言

贝尔-算法 (BellmanFord algorithm)用于计算出起点到各个节点的最短距离,支持存在负权重的情况 它的原理是对图进行最多V-1次松弛操作,得到所有可能的最短路径。

迪杰斯特拉(Dijkstra)算法是典型最短路径算法,用于计算一个节点到其他节点的最短路径。 它的主要特点是以起始点为中心向外层层扩展(广度优先搜索思想),直到扩展到终点为止。 基本思想通过Dijkstra计算图G中的最短路径时,需要指定起点s(即从顶点s开始计算)。

目录

引言

问题描述

最小费用最大流问题

​算法思想 

实现过程

代码实现

python实现如下


问题描述

最小费用最大流问题

最小费用最大流问题是经济学和管理学中的一类典型问题。在一个网络中每段路径都有"容量"和"费用"两个限制条件下,此类问题的研究试图寻找出:流量从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))
  • 2
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

!continue!

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值