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
67
68
69
70
71
72
73
74
75
76
77
|
# 最小费用最大流,dinic+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.p = [0]*N # p 是当前弧优化,跳过已增广的边
self.vis = [0]*N # dfs 过程避免循环
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
pq = [(0,s)]
while pq:
w,u = heappop(pq)
if w>self.d[u]:
continue
for v,_,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
heappush(pq,(nw,v))
return self.d[t]<inf
def dfs(self,u,t,flow): # dfs 得到阻塞流,注意边的费用经过了势能转换
if u==t:
return flow
self.vis[u] = 1
res = 0
for i in range(self.p[u],len(self.g[u])):
self.p[u] += 1
v,j,c,w = self.g[u][i]
nw = self.d[u]+w+self.h[u]-self.h[v]
if c>0 and not self.vis[v] and self.d[v]==nw:
a = self.dfs(v,t,min(flow,c))
flow -= a
self.g[u][i][2]-=a
self.g[v][j][2]+=a
res += a
if flow==0:
break
self.vis[u] = 0
return res
def cal(self,s,t): # 重复增广,维护势能
res = 0
self.spfa(s)
while self.dij(s,t):
tmp = self.dfs(s,t,inf)
for u in range(self.N):
self.h[u] += self.d[u]
res += tmp*self.h[t]
self.p = [0]*self.N
return res
|