1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
|
# 最小费用最大流,EK+dijkstra
from collections import deque
from heapq import heappush,heappop
inf = 10**20
class MCMF:
def __init__(self,N):
self.g = [[] for _ in range(N)] # g 是图中每个 u 对应的 v 列表
self.h = [inf]*N # h 是源点 s 到图中每个 u 的势能
self.d = [inf]*N # d 是图中每个 u 离源点 s 的最小费用距离
self.flow = [0]*N # EK 找增广路时,维护经过每个 u 的流量
self.fa = [-1]*N # EK 找增广路时,维护每个 u 的流量来源
self.N = N
def add(self,u,v,c,w): # 顶点 u 和 v 连边,容量 c,费用 w
self.g[u].append([v,len(self.g[v]),c,w])
self.g[v].append([u,len(self.g[u])-1,0,-w])
def spfa(self,s): # 预处理源点 s 到图中每个 u 的势能
self.h[s] = 0
dq = deque([s])
inq = [0]*self.N
inq[s] = 1
while dq:
u = dq.popleft()
inq[u] = 0
for v,_,c,w in self.g[u]:
if c>0 and self.h[u]+w<self.h[v]:
self.h[v] = self.h[u]+w
if not inq[v]:
inq[v] = 1
dq.append(v)
def dij(self,s,t): # 找单位费用最小的增广路,每条边的费用经过势能转换
self.d = [inf]*self.N
self.d[s] = 0
self.flow[s] = inf
pq = [(0,s)]
while pq:
w,u = heappop(pq)
if w>self.d[u]:
continue
for v,j,c,w2 in self.g[u]:
nw = w+w2+self.h[u]-self.h[v]
if c>0 and nw<self.d[v]:
self.d[v] = nw
self.fa[v] = j
self.flow[v] = min(self.flow[u],c)
heappush(pq,(nw,v))
return self.d[t]<inf
def cal(self,s,t): # 重复增广,维护势能
res = 0
self.spfa(s)
while self.dij(s,t):
a = self.flow[t]
v = t
while v!=s:
j = self.fa[v]
u,i,_,_ = self.g[v][j]
self.g[u][i][2] -= a
self.g[v][j][2] += a
v = u
for u in range(self.N):
self.h[u] += self.d[u]
res += a*self.h[t]
return res
|