[洛谷 P3381] 最小费用最大流 | 模板 Bellman-Ford寻找增广路 入门
Posted PushyTao
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[洛谷 P3381] 最小费用最大流 | 模板 Bellman-Ford寻找增广路 入门相关的知识,希望对你有一定的参考价值。
题目描述
给出一个包含 n n n 个点和 m m m 条边的有向图(下面称其为网络) G = ( V , E ) G=(V,E) G=(V,E),该网络上所有点分别编号为 1 ∼ n 1 \\sim n 1∼n,所有边分别编号为 1 ∼ m 1\\sim m 1∼m,其中该网络的源点为 s s s,汇点为 t t t,网络上的每条边 ( u , v ) (u,v) (u,v) 都有一个流量限制 w ( u , v ) w(u,v) w(u,v)和单位流量的费用 c ( u , v ) c(u,v) c(u,v)。
你需要给每条边 ( u , v ) (u,v) (u,v) 确定一个流量 f ( u , v ) f(u,v) f(u,v),要求:
- 0 ≤ f ( u , v ) ≤ w ( u , v ) 0 \\leq f(u,v) \\leq w(u,v) 0≤f(u,v)≤w(u,v) (每条边的流量不超过其流量限制);
- ∀ p ∈ { V ∖ { s , t } } \\forall p \\in \\{V \\setminus \\{s,t\\}\\} ∀p∈{V∖{s,t}}, ∑ ( i , p ) ∈ E f ( i , p ) = ∑ ( p , i ) ∈ E f ( p , i ) \\sum_{(i,p) \\in E}f(i,p)=\\sum_{(p,i)\\in E}f(p,i) ∑(i,p)∈Ef(i,p)=∑(p,i)∈Ef(p,i)(除了源点和汇点外,其他各点流入的流量和流出的流量相等);
- ∑ ( s , i ) ∈ E f ( s , i ) = ∑ ( i , t ) ∈ E f ( i , t ) \\sum_{(s,i)\\in E}f(s,i)=\\sum_{(i,t)\\in E}f(i,t) ∑(s,i)∈Ef(s,i)=∑(i,t)∈Ef(i,t) (源点流出的流量等于汇点流入的流量)。
定义网络 G G G 的流量 F ( G ) = ∑ ( s , i ) ∈ E f ( s , i ) F(G)=\\sum_{(s,i)\\in E}f(s,i) F(G)=∑(s,i)∈Ef(s,i),网络 G G G 的费用 C ( G ) = ∑ ( i , j ) ∈ E f ( i , j ) × c ( i , j ) C(G)=\\sum_{(i,j)\\in E} f(i,j) \\times c(i,j) C(G)=∑(i,j)∈Ef(i,j)×c(i,j)。
你需要求出该网络的最小费用最大流,即在 F ( G ) F(G) F(G) 最大的前提下,使 C ( G ) C(G) C(G) 最小。
输入格式
输入第一行包含四个整数
n
,
m
,
s
,
t
n,m,s,t
n,m,s,t,分别代表该网络的点数
n
n
n,网络的边数
m
m
m,源点编号
s
s
s,汇点编号
t
t
t。
接下来
m
m
m 行,每行四个整数
u
i
,
v
i
,
w
i
,
c
i
u_i,v_i,w_i,c_i
ui,vi,wi,ci,分别代表第
i
i
i 条边的起点,终点,流量限制,单位流量费用。
输出格式
输出两个整数,分别为该网络的最大流 F ( G ) F(G) F(G),以及在 F ( G ) F(G) F(G) 最大的前提下,该网络的最小费用 C ( G ) C(G) C(G)。
输入输出样例
4 5 4 3
4 2 30 2
4 3 20 3
2 3 20 1
2 1 30 9
1 3 40 5
50 280
说明/提示
对于
100
%
100\\%
100% 的数据,
1
≤
n
≤
5
×
1
0
4
1 \\leq n \\leq 5\\times 10^4
1≤n≤5×104 ,
1
≤
m
≤
5
×
1
0
4
1 \\leq m \\leq 5 \\times 10^4
1≤m≤5×104 ,
1
≤
s
1 \\leq s
1≤s ,
t
≤
n
t \\leq n
t≤n ,
0
≤
w
i
,
c
i
≤
1
0
3
0 \\leq w_i,c_i \\leq 10^3
0≤wi,ci≤103 ,且该网络的最大流和最小费用
≤
2
31
−
1
\\leq 2^{31} - 1
≤231−1
输入数据随机生成。
思路:
和EK算法类似,但每次用
B
e
l
l
m
a
n
−
F
o
r
d
Bellman-Ford
Bellman−Ford 算法而非
B
F
S
BFS
BFS(其实差不多)找增广路。
只要初始流是该流量下的最小费用可行流,每次增广之后的新流都是新流量下的最小费用流。
费用值可正可负
typedef pair<ll, ll> PLL;
struct Edge {
int u, v, cap, flow, cost;
Edge(int _u, int _v, int _cap, int _flow, int _cost) {
u = _u, v = _v, cap = _cap, flow = _flow, cost = _cost;
}
};
struct MinCostMaxFlow {
int n, m;
vector<Edge> edges;
vector<int> G[maxn];
int vis[maxn], dis[maxn], p[maxn], a[maxn];
void init(int x) {
this->n = x;
for (int i = 0; i <= x; i++) G[i].clear();
edges.clear();
}
void add(int u, int v, int cap, int cost) {
edges.push_back(Edge(u, v, cap, 0, cost));
edges.push_back(Edge(v, u, 0, 0, -cost));
m = edges.size();
G[u].push_back(m - 2);
G[v].push_back(m - 1);
}
bool BellmanFord(int s, int t, ll &flow, ll &cost) {
for (int i = 0; i <= n; i++) dis[i] = 0x3f3f3f3f;
memset(vis, 0, sizeof vis);
queue<int> que;
que.push(s);
dis[s] = 0, vis[s] = 0, p[s] = 0, a[s] = 0x3f3f3f3f;
while (que.size()) {
int u = que.front();
que.pop();
vis[u] = 0; /// not in the queue
for (int i = 0; i < G[u].size(); i++) {
int id = G[u][i];
Edge e = edges[id];
int to = e.v;
if (e.cap > e.flow && dis[to] > dis[u] + e.cost) {
dis[to] = dis[u] + e.cost;
p[to] = id;
a[to] = min(a[u], e.cap - e.flow);
if (!vis[to]) {
que.push(to[洛谷 P3381] 最小费用最大流 | 模板 Bellman-Ford寻找增广路 入门