python实现最大流算法(Push-Relabel算法)-图算法

一.最大流问题

 

 

二.解决最大流的相关算法Push-Relabel算法

二.伪代码

push-relabel伪代码:

Initialize();
WHILE 存在盈余点 DO
    选择最大高度盈余点v;
    IF ∃e(v,w)满足h(v)=h(w)+1
    THEN    Push( v, e);
    ELSE    h(v)++; //Relabel
ENDWHILE

push的伪代码:

IF α_f(v)≥r_e THEN
    Δ=r_e;  //饱和推送
ELSE
    Δ=α_f(v);  //非饱和推送
在边e上推送Δ单位的流;
更新剩余容量r_e 

Initialize()伪代码(高度不变式):

f=0;
“反向BFS”设置高度值;
h(s)=n;
FOR v∈δ^+(s) DO
    在e(s,v)上饱和推送;
ENDFOR

三.项目代码

from collections import defaultdict
edges=defaultdict(list)#记录每条边的容量和边的信息
nodes=[]#记录图中的点
profit={}#记录每个点的盈余,前提是顶点是已经编号好的
opposite_edges=defaultdict(list)



def read_file(filepath,nodes,edges,opposite_edges):
    """读取文件数据"""
    f=open(filepath,"r");
    graph_node_num=int(f.readline().strip())
    graph_edge_num=int(f.readline().strip())
    for _ in range(graph_edge_num):
        node_a,node_b,edge_c=f.readline().split()
        if node_a not in nodes:
            nodes.append(node_a)
        if node_b not in nodes:
            nodes.append(node_b)
        edges[node_a].append([node_a,node_b,int(edge_c)])
        opposite_edges[node_b].append((node_b,node_a))
    start_node,end_node=f.readline().split()
    return start_node,end_node,graph_node_num



def BFS(opposite_edges,end_node,Hight):
    """BFS反向设置层号+层号就是高度"""
    queue=[]#设置一个队列
    visited=[]
    visited.append(end_node)
    for i in opposite_edges[end_node]:
        node_a,node_b=i
        queue.append(node_b)
        visited.append(node_b)
        Hight[int(node_b)]=Hight[int(node_a)]+1
    while len(queue)!=0: #队列不为空就一直进行循环
        node=queue.pop(0)
        for i in opposite_edges[node]:
            node_c,node_d=i
            if node_d not in visited: #邻接点没有被探索,就高度加1,并把这个邻接点加入队列
                Hight[int(node_d)]=Hight[int(node_c)]+1
                queue.append(node_d)
                visited.append(node_d)
        pass
    pass



def push(node_a, edge, node_b, profit, edges):
    """push操作"""
    if profit[node_a] >= edge:  # 饱和推送
        flow_edge = edge
    else:  # 非饱和推送
        flow_edge = profit[node_a]
    profit[node_a] = profit[node_a] - flow_edge  # 更新node_a点上的盈余
    profit[node_b]=profit[node_b]+flow_edge  #更新node_b点上的盈余
    flag=1 #设置一个标志位
    k=0
    for line in edges[node_b]:  #如果以前存在这条反向边,更新
        if line[1]==node_a :
            edges[node_b][k][2]= edges[node_b][k][2]+flow_edge
            flag=0
            break
        k=k+1
    if flag==1:  #之前不存的话,就增加
        edges[node_b].append([node_b,node_a,flow_edge])
    j = 0
    #更新原来边上的容量
    for i in edges[node_a]:
        if i[1] == node_b:
            edges[node_a][j][2]=edge-flow_edge
        j=j+1



def initialize(opposite_edges,edges,nodes,start_node,end_node,Hight,graph_node_num,profit):
    """初始化操作"""
    Hight[int(end_node)]=0
    BFS(opposite_edges,end_node,Hight)#BFS反向设置层号
    Hight[int(start_node)]=graph_node_num  #保持高度不变式
    for i in nodes:
          profit[i]=0  #初始化,所有点的盈余为0
    k=0
    for line in edges[start_node]:  #设置起始点的盈余
        profit[start_node]=profit[start_node]+line[2]
    for line in  edges[start_node]:
        node_a,node_b,edge_c=line
        push(node_a,edge_c,node_b,profit, edges) #在起点的所有邻接边上进行推送



def select_high(Hight,profit,nodes,start_node,end_node):
    """选择最大高度的盈余点"""
    max=0
    for i in nodes:
      if i !=start_node  and i !=end_node:
        if profit[i]!=0: #先确保有盈余
            if Hight[int(i)]>=max:  #选择高度最大
                max=Hight[int(i)]
                node=i
    return node



def Push_Relabel(edges,nodes,start_node,end_node,opposite_edges,Hight, graph_node_num,profit):
    """push和Relabel操作"""
    initialize(opposite_edges, edges,nodes,start_node, end_node, Hight, graph_node_num,profit)
    ans=1
    while ans!=0:
        #选择最大高度的盈余点
        node_v=select_high(Hight,profit,nodes,start_node,end_node)
        flag=1#设置一个标志位
        for line in edges[node_v]:  #寻找node_v的邻接边,发现有满足的“下山”方向的边就进行push操作
             node_v,node_w,edge_c=line
             if Hight[int(node_v)]==(Hight[int(node_w)]+1) and edge_c!=0: #满足高度不变式,并且边存在的话
                 push(node_v,edge_c,node_w,profit,edges)
                 flag=0

        if flag==1:  #不存在这样的边就进行relabel操作
            Hight[int(node_v)]=Hight[int(node_v)]+1
        ans = 0
        for i in profit.values():
            ans = ans + i
        ans = ans - profit[end_node] - profit[start_node]  #计算V-{s,t}中所有点中的盈余 盈余为0时,证明已经找到了最大流




start_node,end_node,graph_node_num=read_file("project9-test3",nodes,edges,opposite_edges)
Hight=[0]
for i in nodes:
    Hight.append(0)
Push_Relabel(edges,nodes,start_node,end_node,opposite_edges,Hight, graph_node_num,profit)
print("最大流为:",profit[end_node])

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
网络最大流问题是一个基本的组合最优化问题,旨在寻找一个可行流 f∗,使其流量 v(f) 达到最大值。这个问题在网络流理论中有着广泛的应用。在Python中,你可以使用不同的算法来解决网络最大流问题。 其中一个常用的算法是Ford-Fulkerson算法,它是基于增广路径的方法。该算法通过不断寻找增广路径,并更新流量来达到最大流的目标。你可以使用Python实现这个算法,并通过网络中的节点和边的数量来评估算法的时间复杂度。 另外一个常用的算法是Edmonds-Karp算法,它是Ford-Fulkerson算法的一种优化版本。该算法使用广度优先搜索来寻找增广路径,从而提高了算法的效率。同样地,你也可以使用Python实现Edmonds-Karp算法。 在解决网络最大流问题时,你可以使用Python的网络流库,如NetworkX,来构建网络并应用最大流算法。这些库通常提供了丰富的功能和易于使用的接口,以帮助你解决网络最大流问题。 总之,网络最大流问题是一个基本的组合最优化问题,可以使用不同的算法来解决。在Python中,你可以使用自己实现算法或使用网络流库来解决这个问题。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [【运筹优化】网络最大流问题及三种求解算法详解 + Python代码实现](https://blog.csdn.net/weixin_51545953/article/details/129009589)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *3* [python实现Ford-Fulkerson算法--最大流问题](https://blog.csdn.net/m0_62410163/article/details/130650433)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

一个编程的菜鸡

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

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

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

打赏作者

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

抵扣说明:

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

余额充值