Network flow and bipartite graph

Keywords: Graph Theory

0. Change log

2021.12.5: replace template code. Add a bipartite chart.

1. Network flow

The key of network flow is modeling. Modeling is the essence and modeling is human wisdom.

1.1. Maximum network flow

Maximum Flow, MF for short.

A directed graph network \ (G=(V,E) \), gives the source and sink \ (S,T \), and each edge \ ((u,v) \) has capacity \ (c(u,v) \). In particular, if \ ((u,v) \notin E \), then \ (c(u,v)=0 \). Find the maximum traffic that can be streamed by \ (S\to T \).

  • Stream function: let \ (f(x,y) \) be a binary function of \ ((x,y)\to\mathbb R \), where \ (x,y\in V \). It satisfies the following properties:
    • Capacity limit: the flow of each side does not exceed the capacity, i.e. \ (f(x,y)\leq c(x,y) \).
    • Skew symmetry: \ (f(x,y)=-f(y,x) \).
    • Flow conservation: except for the source and sink points, the inflow and outflow flows from each node are equal, i.e. \ (\ forall x\neq S,x\neq T \), \ (\ sum {(U, x) \ in e}f (U, x) = \ sum {(x, V) \ in e}f (x, V) \).
  • Residual network: a directed graph composed of \ ((x,y) \) of all \ (f(x,y)\neq c(x,y) \).
  • Augmented path: a path of \ (S\to T \), which satisfies that all edges on the path are in the residual network.

The core idea of the algorithm is to add the capacity of the opposite side of the current side to the increased traffic of the current side every time. The purpose of this is to go back: take back part of the flow given. Therefore, network flow is similar to reversible greed.

Skill: network flow mapping generally uses chained forward stars. Each edge and its reverse edge are stored continuously. The numbers are recorded as \ (i \) and \ (i+1 \), \ (i \) is an even number. You can quickly find that the reverse side number of \ (i \) is \ (i\oplus 1 \), which is very convenient. Therefore, the initial \ (cnt \) should be set to \ (1 \).

1.1.1. Maximum flow = minimum cut

Divide \ (V \) into two disjoint point sets \ (A,B \), in which \ (S\in A \), \ (T\in B \), which is called cut. Define the cut capacity as \ (\ sum_{x\in A,y\in B}c(x,y) \). For any feasible flow, we know that its flow is the sum of the flows of all cutting edges of any cut (perceptual understanding). Due to capacity constraints, it is obviously not greater than the capacity of the cut, so the flow of any flow is not greater than the capacity of any cut. The maximum flow obviously satisfies that \ (S,T \) on the residue network is not connected, so it is easy to find such a cut so that the sum of the edge cutting flows is equal to the capacity of the cut, that is, the maximum flow = the minimum cut.

1.1.2. EK algorithm

Edmonds - Karp, or EK for short.

Core idea: constantly find the widening path with the smallest length for widening, and realize BFS. It is necessary to record the number of edges flowing to each point, and then continuously push back from \ (T \) to \ (S \). Time complexity \ (\ mathcal{O}(nm^2) \).

int cnt = 1, hd[N], to[M << 1], nxt[M << 1], lim[M << 1];
void add(int u, int v, int w) {
	nxt[++cnt] = hd[u], hd[u] = cnt, to[cnt] = v, lim[cnt] = w;
	nxt[++cnt] = hd[v], hd[v] = cnt, to[cnt] = u, lim[cnt] = 0;
} int n, m, s, t, fr[N], vis[N], fl[N]; ll ans;
int main(){
	cin >> n >> m >> s >> t;
	for(int i = 1, u, v, w; i <= m; i++) cin >> u >> v >> w, add(u, v, w);
	while(1) {
		queue <int> q; mem(fl, 0, N), mem(vis, 0, N);
		fl[s] = inf, vis[s] = 1, q.push(s);
		while(!q.empty()) {
			int t = q.front(); q.pop();
			for(int i = hd[t]; i; i = nxt[i]) {
				int it = to[i];
				if(!lim[i] || vis[it]) continue;
				vis[it] = 1, fl[it] = min(fl[t], lim[i]);
				fr[it] = i ^ 1, q.push(it);
			}
		} if(!fl[t]) break;
		int p = t; ans += fl[t];
		while(p != s) lim[fr[p]] += fl[t], lim[fr[p] ^ 1] -= fl[t], p = to[fr[p]];
	} cout << ans << endl;
}

1.1.3. Dinic algorithm

Core idea: BFS layered finding \ (dis_x \) means that from \ (S \) to \ (x \) at least passes through the \ (dis_x \) edge on the residual network. As we all know, this is a directed acyclic layered graph. Only expand between two layers \ (dis_y=dis_x+1 \). Because it is DAG, DFS multi-channel can be expanded.

Current arc Optimization: when expanding, the edge with capacity equal to flow is useless and can be skipped directly. Record the first edge not full from each point, which is called the current arc. Each time DFS reaches this point, it expands from the current arc. Note that before each multi-channel augmentation, the current arc should be initialized as the head of the chain forward star, because it is not that once the traffic is equal to the capacity, this edge will never be used: the increase of the traffic on the reverse edge will make it reappear in the residual network. The Dinic time complexity of the current arc optimization \ (\ mathcal{O}(n^2m) \), if not added, will degenerate to \ (\ mathcal{O}(nm^2) \).

Notes on current arc Optimization:

for(int i = cur[u]; res && i; i = nxt[i]) {
	cur[u] = i;
    // ......
}

The above code cannot be written as:

for(int &i = cur[u]; res && i; i = nxt[i]) {
    // ......
}

Because if the edge of \ (u\to v \) changes the remaining traffic res to \ (0 \), the second writing method will directly skip \ ((u,v) \), but in fact \ ((u,v) \) is not necessarily full, so it should not be skipped. This will cause the current arc to skip many edges that should not jump, reduce the amplification efficiency, and greatly reduce the program running efficiency (the actual performance is worse than EK).

Another solution is to determine if(!res) return flow; at the end of the loop;. In short, when writing the current arc optimization, be careful not to skip the edge that is not full. Template question P3381 [template] minimum cost maximum flow The code is as follows:

int cnt = 1, hd[N], to[M << 1], nxt[M << 1], lim[M << 1];
void add(int u, int v, int w) {
	nxt[++cnt] = hd[u], hd[u] = cnt, to[cnt] = v, lim[cnt] = w;
	nxt[++cnt] = hd[v], hd[v] = cnt, to[cnt] = u, lim[cnt] = 0;
} int n, m, s, t, dis[N], cur[N]; ll ans;
ll dfs(int u, ll res) {
	if(u == t || !res) return res; ll flow = 0;
	for(int i = cur[u]; res && i; i = nxt[i]) {
		int it = to[i], c = min(res, (ll)lim[i]); cur[u] = i;
		if(c && dis[u] + 1 == dis[it]) {
			ll k = dfs(it, c);
			flow += k, res -= k, lim[i] -= k, lim[i ^ 1] += k;
		}
	} return dis[u] = flow ? dis[u] : 0, flow;
}
int main(){
	cin >> n >> m >> s >> t;
	for(int i = 1, u, v, w; i <= m; i++) cin >> u >> v >> w, add(u, v, w);
	while(1) {
		queue <int> q; mem(dis, 0x3f, N), dis[s] = 0, q.push(s);
		while(!q.empty()) {
			int t = q.front(); q.pop();
			for(int i = hd[t]; i; i = nxt[i])
				if(lim[i] && dis[to[i]] > 1e9)
					dis[to[i]] = dis[t] + 1, q.push(to[i]);
		} if(dis[t] > 1e9) break; cpy(cur, hd, N), ans += dfs(s, 1e18);
	} cout << ans << endl;
}

1.1.4. ISAP

1.1.5. HLPP

1.2. Minimum cost maximum flow

Minimum cost maximum flow, MCMF for short. Compared with the maximum flow of general networks, on the basis of the original network, each edge has an additional weight \ (w(x,y) \). When the maximum flow is guaranteed, it is necessary to find the minimum value of \ (\ sum_{(x,y)\in E}f(x,y)w(x,y) \).

1.2.1. SSP algorithm without negative ring

Successful shortest path, SSP for short.

Core idea: find the shortest widening road every time.

  • EK: replace BFS with SPFA.
  • Dinic: replace BFS with SPFA. During multi-channel expansion, it is only expanded between \ (x,y \) of \ (dis_x+w(x,y)=dis_y \).

Time complexity \ (\ mathcal{O}(nmf) \), where \ (f \) is the maximum flow. In practical application, this upper bound is very loose, because not only the number of augmentation is far less than \ (f \), but also the complexity of SPFA is far less than \ (nm \). For correctness proof, see OI-Wiki.

1.2.2. Primal dual primal dual algorithm without negative ring

It is recommended to learn Johnson's full source shortest path algorithm first.

Specifically, we assign a "potential" \ (h_i \) to each point to keep the shortest path of the original graph unchanged. Using the idea of Johnson's all source shortest path algorithm, first calculate the shortest path \ (h_i \) from the source point to each point with SPFA, then the new edge weight of \ (i\to j \) is \ (w_{i,j}+h_i-h_j \). The correctness proof is omitted.

After finding the augmented path, each augmented path will change the shape of the graph. We only need to add the shortest path running during each augmented path to \ (H \), that is \ (h_i\gets h_i+dis_i \). The reasons are as follows:

  • If \ (i\to j \) is on Zengguang Road, there is \ (dis_i+w_{i,j}+(h_i-h_j)=dis_j \). That is \ (w_{j,i}+(dis_j+h_j)-(dis_i+h_i)=0 \) (\ (w_{i,j}=-w_{j,i} \)), and the opposite edge weight is \ (0 \).
  • For the original edge, we have \ (dis_i+w_{i,j}+(h_i-h_j)\geq dis_j \), that is \ (w_{i,j}+(dis_i+h_i)-(dis_j+h_j)\geq 0 \, and the edge weight is still non negative.

After the above transformation, we can use Dijkstra instead of SPFA to solve the augmented path. Compared with SSP, it has no great advantage in practical application. Charge flow template code:

const int N = 5e3 + 5;
const int M = 5e4 + 5;
int cnt = 1, hd[N], to[M << 1], nxt[M << 1], lim[M << 1], cst[M << 1];
void add(int u, int v, int w, int c) {
	nxt[++cnt] = hd[u], hd[u] = cnt, to[cnt] = v, lim[cnt] = w, cst[cnt] = c;
	nxt[++cnt] = hd[v], hd[v] = cnt, to[cnt] = u, lim[cnt] = 0, cst[cnt] = -c;
} int n, m, s, t, h[N], vis[N], dis[N], fr[N], flow, cost;
int main(){
	cin >> n >> m >> s >> t;
	for(int i = 1, u, v, w, c; i <= m; i++) cin >> u >> v >> w >> c, add(u, v, w, c);
	queue <int> q; mem(h, 0x3f, N), h[s] = 0, q.push(s);
	while(!q.empty()) {
		int t = q.front(); q.pop(); vis[t] = 0;
		for(int i = hd[t]; i; i = nxt[i]) if(lim[i]) {
			int it = to[i], d = h[t] + cst[i];
			if(d < h[it]) {h[it] = d; if(!vis[it]) vis[it] = 1, q.push(it);}
		}
	} while(1) {
		priority_queue <pii, vector <pii>, greater <pii>> q;
		mem(dis, 0x3f, N), mem(vis, 0, N), q.push({dis[s] = 0, s});
		while(!q.empty()) {
			pii t = q.top(); q.pop();
			if(vis[t.se]) continue; vis[t.se] = 1;
			for(int i = hd[t.se]; i; i = nxt[i]) if(lim[i]) {
				int it = to[i], d = t.fi + cst[i] + h[t.se] - h[it];
				if(d < dis[it]) fr[it] = i, q.push({dis[it] = d, it});
			}
		} if(dis[t] > 1e9) break;
		int c = (1ll << 31) - 1;
		for(int i = 1; i <= n; i++) h[i] += dis[i];
		for(int i = t; i != s; i = to[fr[i] ^ 1]) cmin(c, lim[fr[i]]);
		for(int i = t; i != s; i = to[fr[i] ^ 1]) lim[fr[i]] -= c, lim[fr[i] ^ 1] += c;
		flow += c, cost += h[t] * c;
	} cout << flow << " " << cost << "\n";
}

1.3. Examples

I. P4249 [WC2007] scissors stone cloth

Now that you have a certain understanding of the basic principles of network flow, let's take a look at the following simple example and apply the knowledge we just learned to practice.

Note that for any three different points \ (i,j,k \), if they cannot form a ternary ring, there must be and only one point defeats the other two points. Enumerate this point \ (I \), then any two of its outgoing points \ (j,k \) cannot form a ternary ring. So the final answer is \ (\ dbinom n 3 - \ sum {\ \ I = 1} ^ n \ dbinom {deg_i} 2 \). Therefore, we need to minimize \ (\ sum {\ \ I = 1} ^ n \ dbinom {deg_i} 2 \).

The core of this topic: the contribution of the number of disassembled combinations. Writing \ (\ dbinom x 2 \) as \ (1+2+\cdots+x \) inspired us to use network flow: abstracting the undirected edge \ ((u,v) \) into a node \ (c \)\ (S\to c \), \ (c\to u \), \ (c\to v \) are all connected with an edge with a capacity of \ (1 \) and a cost of \ (0 \), indicating that there is and only one point is selected. In addition, connect several lines from each point \ (U \) to \ (T \), with a capacity of \ (1 \), at the cost of \ (deg_, deg_ + 1, \ cdots, n-1 \), where \ (deg_ \) is the exit of \ (U \) in the determined edge, and then run MCMF.

2. Bipartite graph

2.1. Definition, judgment and nature

Definition of bipartite graph: suppose that an undirected graph \ (G=(V,E) \), if \ (V \) can be divided into two point sets \ (V_1,V_2 \), it satisfies: \ (V_1\cap V_2=\varnothing \), \ (V_1\cup V_2=V \) and \ (\ forall (u,v)\in E \) all satisfy that \ (u,v \) belongs to \ (V_1 \) or \ (V_2 \), then \ (G \) is a bipartite graph.

The necessary and sufficient condition for a graph to be a bipartite graph is that there is no odd ring. Necessity: starting from any point, you must pass through an even number of edges to return to this point; Sufficiency: for graphs without odd rings, black-and-white coloring can obtain a set of schemes for partition \ (V_1,V_2 \).

Through this property, we get a method to quickly determine a bipartite graph in linear time \ (|V|+|E124\): black and white coloring the connected block from any node that is not dyed. If there is an edge so that the colors of the two ends are the same, there is an odd ring, not a bipartite graph. On the contrary, it is a bipartite graph.

2.2. Maximum matching

The definition of bipartite graph matching is as follows: given a bipartite graph \ (G=(V,E) \), if its edge derived subgraph \ (G '= (V',E')\subseteq G \) satisfies that any two edges in \ (E' \) do not intersect at the same endpoint, then \ (G '\) is a set of matching of bipartite graph \ (g \).

  • Edge derived Subgraph: a graph composed of several edges and all vertices connected with these edges.
  • Point derived Subgraph: a graph composed of several points with both ends on all edges of the point set.

Divide \ (V \) into two point sets \ (V_1,V_2 \) that do not intersect each other and have no edges inside. For any node, at most one edge \ ((u,v)\in E '\) can be connected to it, that is, the degree \ (\ leq 1 \) is limited.

2.2.1. Hungarian algorithm

2.2.2. Network flow

Try to solve this problem with network flow: connect the edge from the source point \ (S \) to each node \ (V_1 \), connect the edge from each node \ (V_2 \) to the sink point \ (T \), and add the edge of the original graph. Set the capacity of all edges to \ (1 \), and the maximum flow of \ (S\to T \) is the maximum matching. It is not difficult to prove the correctness: a set of feasible flows corresponds to a set of matching one by one, and the flow is equal to the matching quantity.

Using Dinic to find the maximum flow of the network, the time complexity is magical \ (\ mathcal{O}(E\sqrt {V}) \), and the proof is shown in OI-Wiki . Template question P3386 [template] bipartite graph maximum matching The code is as follows.

const int N = 1e3 + 5;
const int M = 1e5 + 5;
int cnt = 1, hd[N], to[M << 1], nxt[M << 1], lim[M << 1];
void add(int u, int v) {
	nxt[++cnt] = hd[u], hd[u] = cnt, to[cnt] = v, lim[cnt] = 1;
	nxt[++cnt] = hd[v], hd[v] = cnt, to[cnt] = u, lim[cnt] = 0;
} int n, m, e, t, ans, dis[N], cur[N];
int dfs(int id, int res) {
	if(id == t || !res) return res;
	int flow = 0;
	for(int i = cur[id]; i && res; i = nxt[i]) {
		int it = to[i], c = min(lim[i], res); cur[id] = i;
		if(c && dis[id] + 1 == dis[it]) {
			int k = dfs(it, c);
			res -= k, flow += k, lim[i] -= k, lim[i ^ 1] += k; 
		}
	} return dis[id] = flow ? dis[id] : -1, flow;
}
int main(){
	cin >> n >> m >> e, t = n + m + 1;
	for(int i = 1, u, v; i <= e; i++) cin >> u >> v, add(u, v + n);
	for(int i = 1; i <= n; i++) add(0, i);
	for(int i = 1; i <= m; i++) add(n + i, t);
	while(1) {
		queue <int> q; mem(dis, 0x3f, N), dis[0] = 0, q.push(0);
		while(!q.empty()) {
			int t = q.front(); q.pop();
			for(int i = hd[t]; i; i = nxt[i]) if(lim[i]) {
				int it = to[i], d = dis[t] + 1;
				if(d < dis[it]) dis[it] = d, q.push(it);
			}
		} if(dis[t] > t) break; cpy(cur, hd, N), ans += dfs(0, N);
	} cout << ans << endl;
}

2.3. Minimum point covering set

The definition of bipartite graph point covering set is as follows: given a bipartite graph \ (G=(V,E) \), if the point set \ (V'\subseteq V \) satisfies that there are \ (u\in V' \) or \ (v\in V '\) for any \ ((u,v)\in E \), then \ (V' \) is an covering set of bipartite graph \ (G \). i.e. a point can cover the edge with this point as the endpoint, and find the minimum point set covering all edges.

The point covering set of a bipartite graph corresponds to a set of cuts: build the graph when we find the maximum match, and we decide that the cuts are only taken at both ends. If the edge between two points is taken, it can be adjusted to both ends, that is, cutting \ ((u,v) \) is equivalent to cutting off \ ((S,u) \) or \ ((v,T) \), because if there is flow between \ (u,v \), then \ (S\to u\to v\to T \) is obviously full. For the left point \ (u\in V_1 \), if \ (S\to u \) is cut off, then \ (U \) belongs to the minimum point covering set. Similarly, if the right point \ (v\in V_2 \) satisfies that \ (v\to T \) is cut off, \ (V \) also belongs to the minimum point covering set.

The above construction is a point covering set of combinatorial method. The counter proof method can prove that if there is an edge \ ((u,v)\in E \) that is not covered, it indicates that \ (S\to u\to v\to E \) has an augmented path, which is inconsistent with the definition of cut. To sum up, the minimum point covering set is equal to the minimum cut, that is, the maximum flow, that is, the maximum matching of bipartite graph.

2.4. Maximum independent set

The definition of independent set of bipartite graph is as follows: given a bipartite graph \ (G=(V,E) \), if the point set \ (V '\ subseteq V \) satisfies that there is no edge for any two points in the point set, then \ (V' \) is an independent set of bipartite graph \ (G \).

Consider the minimum point covering set \ (V '\) of bipartite graph \ (G=(V,E) \). Because each edge is covered by at least one \ (u\in V '\), all points of \ (V\backslash V' \) are not connected to each other. In fact, the independent set corresponds to the point covering set one by one, and the intersection of the independent set and the point covering set is empty and \ (V \), that is, the point covering set and the independent set are complementary. Therefore, the maximum independent set of bipartite graph is equal to \ (|v124\) minus the minimum point covering set.

2.5. Maximum mission

The clique of a bipartite graph is defined as follows: given a bipartite graph \ (G=(V,E) \), if its point derived subgraph \ (G'=(V',E ') \) satisfies the requirement to divide \ (V' \) into complementary point sets \ (V_1,V_2 \), there is \ ((u,v)\in E '\) for any \ (u\in V_1,v\in V_2 \), then \ (G' \) is a clique of a bipartite graph \ (g \).

Create a supplementary graph \ (G'=(V',E ') \) of \ (g \). If \ ((u,v)\in E' \), then \ (u,v \) cannot appear in the largest clique at the same time. Therefore, the maximum clique of a bipartite graph is equal to the maximum independent set of a complementary graph.

Maximum clique algorithm to make \ (V_1 \) or \ (V_2 \) as large as possible: maximum clique \ (\ sim \) maximum independent set of complementary graph \ (\ sim \) complement of minimum point covering set of complementary graph. Let us make the \ (|V_1124\) in the largest clique as large as possible, and the corresponding is to make the \ (|V_1124\) covered by the smallest point of the complementary graph as small as possible. According to the conclusion "the point covering set of a bipartite graph corresponds to a set of cuts" (it is proved in 2.3), the problem is equivalent to finding the minimum cut of the complementary graph \ (G '= (V',E ') \) of the original bipartite graph \ (g \), so that the cut points in \ (V_1\in V' \) are as few as possible.

If we only run the maximum flow on the original graph, we cannot control the number of points cut off at a point in the bipartite graph. We consider how to attach weights to each edge without affecting the maximum matching, so that the minimum cut we calculated can cut the edge between \ (v\in V_2 \) and \ (T \).

It is advisable to attach the weight \ (c+1 \) to the edge between \ (S \) and \ (u\in V_1 \), and attach the weight \ (C \) to the edge between \ (v\in V_2 \) and \ (T \), so that \ ((v,T) \) can be cut preferentially and \ (V_1 \) can be cut as few points as possible. However, in order to ensure the correctness of the maximum matching, \ (C \) should not be less than \ (n=\min(|V_1|,|V_2|): the case that \ (x \) left points match \ (Y > x \) right points, i.e. \ ((n-1) \ times (c+1) < NC \), which is simplified to \ (c > n-1 \). Don'T forget to attach \ (n \) to the edge weight between \ ((u,v)\in E \): because the capacity of \ ((v,T) \) is limited to \ (n \), \ ((u,v) \) can'T exceed \ (n \), so attach it as \ (n \).

2.6. Examples

*1. [bzoj2162] boys and girls

This problem can be regarded as two separate parts. One part is to find the maximum clique of bipartite graph, and the other part needs binomial inversion. See Inversion and Dirichlet convolution Part 2. Binomial inversion.

Posted by defect on Sun, 05 Dec 2021 10:46:03 -0800