'''
FordFulkerson思想解决有向图的最大流问题
增广路用Edmonsd-Karp算法查找
'''
from typing import List
from collections import deque
class FortdFulkerson:
# 输入图中所有边列表[(from1, to1, weight1), (form2, to2, weight2), ......]
# souece_node 和 end_node 分别为源点和汇点
def __init__(self, edges, source_node, end_node):
self.edges = edges[::]
self.source_node = source_node
self.end_node = end_node
# 获取增广路径(Edmonsd-Karp算法)
def __getResidulePath(self, residule_link) -> List:
que = deque()
que.append(self.source_node)
visited = set()
visited.add(self.source_node)
pre = {self.source_node: (None, None)} # 到当前状态经历的上一条边
while len(que) > 0:
cur = que.popleft()
if cur == self.end_node:
break
for next in residule_link[cur]:
if next not in visited and len(residule_link[cur][next]) > 0:
for edge_idx, (edge_w, _) in enumerate(residule_link[cur][next]):
if edge_w > 0:
que.append(next)
visited.add(next)
pre[next] = (cur, edge_idx)
if self.end_node not in pre:
return None
path = []
cur, edge_idx, next = self.end_node, 0, None
while cur is not None:
if next:
path.append((cur, next, edge_idx)) # 到next是经过cur指向next的第edge_idx条边到的
cur, edge_idx, next = pre[cur][0], pre[cur][1], cur
return path[::-1]
#返回整个图的最大流和每条边的流量以及容量,(max_flow, [(from1, to1, flow1, weight1), (from1, to1, flow1, weight1), ......])
def getMaxFlow(self):
# 根据边构造流量图和残量图
flow_link, residule_link = {}, {}
for a, b, w in self.edges:
if a not in flow_link:
flow_link[a] = {}
if b not in flow_link[a]:
flow_link[a][b] = []
flow_link[a][b].append(w)
if a not in residule_link:
residule_link[a] = {}
if b not in residule_link[a]:
residule_link[a][b] = []
residule_link[a][b].append([w, (a, b, len(flow_link[a][b])-1)]) # [边权值,(对应原图边起点,对应原图边终点,对应原图边序号)]
if b not in residule_link:
residule_link[b] = {}
if a not in residule_link[b]:
residule_link[b][a] = []
residule_link[b][a].append([0, (a, b, len(flow_link[a][b])-1)])
max_flow = 0
while True:
path = self.__getResidulePath(residule_link)
if path is None:
break
# 找路径中最小的边的权值
min_weight = 0x7fffffff
for a, b, edge_idx in path:
min_weight = min(min_weight, residule_link[a][b][edge_idx][0])
# 更新残量图
for a, b, edge_idx in path:
residule_link[a][b][edge_idx][0] -= min_weight
residule_link[b][a][edge_idx][0] += min_weight
aa, bb, idx = residule_link[a][b][edge_idx][1] # 获取原图边的起点终点和序号
if aa in flow_link and bb in flow_link[aa]:
if aa == a:
flow_link[aa][bb][idx] += min_weight
else:
flow_link[aa][bb][idx] -= min_weight
max_flow += min_weight
ans = []
for a in flow_link:
for b in flow_link[a]:
for w in flow_link[a][b]:
ans.append((a, b, w))
return max_flow, ans
n, m, start, end = map(int, input().split())
link = {}
for _ in range(m):
a, b, w = map(int, input().split())
if (a, b) not in link:
link[(a, b)] = w
else:
#print(f'overlap {a} {b}')
link[(a, b)] += w
edges = [(a, b, w) for (a, b), w in link.items()]
algo = FortdFulkerson(edges, start, end)
print(algo.getMaxFlow()[0])