问题描述
顾名思义,多源汇最大流问题就是含有多个源点和汇点的最大流问题,和普通的最大流问题不同。在次问题下,图中有sn个源点,sm个汇点,需要求此条件下的最大流。
解题思路
一般网络流题目的思考方式是比较固定的,先按照直觉和以往的做题经验建图,然后尝试证明原问题的解集和流网络中的可行流是一一对应的,最后直接打板子结局问题,难点在建图和证明。
多远会最大流问题的建图其实很简单很好想,直觉上判断就是建立一个虚拟源点,连向所有的源点,容量为正无穷,然后建立一个虚拟汇点,从所有的汇点向虚拟汇点连边,容量也为正无穷。那么主观上感觉,原图中的可行流和新图中的可行流是一一对应关系的。
证明其实很简单,对于原图中的任一可行流,我们建立虚拟源点和虚拟汇点,然后一次计算出每个源点流出的流量,然后从虚拟源点向此点流相同流量,对于虚拟汇点也如此操作,就可以建得到新图的一个可行流。反之,从新图中直接删掉源点和汇点就可以得到原图的一个可行流,这样就证明了一一对应的关系。
所以解题的策略就是建新图,执行Dinic算法,求出的最大流就是原问题的答案
示例代码
#include<bits/stdc++.h>
using i64 = long long;
constexpr int inf = 1E8;
void solve() {
int n , m , sc , st;
std::cin >> n >> m >> sc >> st;
std::vector<int> s(sc) , t(st);
for(auto &it : s) std::cin >> it , it --;
for(auto &it : t) std::cin >> it , it --;
std::vector<int> h(n + 10 , -1) , e , ne , f;
auto add = [&](int a , int b , int c) {
e.push_back(b) , ne.push_back(h[a]) , f.push_back(c) , h[a] = e.size() - 1;
e.push_back(a) , ne.push_back(h[b]) , f.push_back(0) , h[b] = e.size() - 1;
};
for(int i = 0 ; i < m ; i ++) {
int a , b , c;
std::cin >> a >> b >> c;
add(a - 1 , b - 1 , c);
}
int S = n , T = n + 1; //建立超级源点和汇点
for(auto it : s) add(S , it , inf);
for(auto it : t) add(it , T , inf);
std::vector<int> d(n + 10) , cur(n + 10);
auto bfs = [&]() {
std::queue<int> q;
q.push(S);
for(auto &it : d) it = -1;
d[S] = 0;
cur[S] = h[S];
while(!q.empty()) {
auto u = q.front();
q.pop();
for(int i = h[u] ; ~i ; i = ne[i]) {
int ver = e[i];
if(d[ver] == -1 && f[i]) {
d[ver] = d[u] + 1;
cur[ver] = h[ver];
if(ver == T) return true;
q.push(ver);
}
}
}
return false;
};
auto dfs = [&](auto &self , int u , int limit) -> int {
if(u == T) return limit;
int flow = 0;
for(int i = cur[u] ; ~i && flow < limit ; i = ne[i]) {
cur[u] = i;
int ver = e[i];
if(d[ver] == d[u] + 1 && f[i]) {
int t = self(self , ver , std::min(limit - flow , f[i]));
if(!t) d[ver] = -1;
f[i] -= t , f[i ^ 1] += t , flow += t;
}
}
return flow;
};
auto dinic = [&]() {
int res = 0 , flow;
while(bfs()) while(flow = dfs(dfs , S , inf)) res += flow;
return res;
};
std::cout << dinic() << '\n';
}
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
std::cout.tie(nullptr);
int t = 1;
//std::cin >> t;
while(t --) {
solve();
}
return 0;
}