#include<bits/stdc++.h> #define N 1000001 #define int long long
usingnamespacestd;
int n, p, q, S, T; int cnt = 1, head[N], deep[N], cur[N]; int k;
structEdge { int to, f, nxt; }edge[N];
inlinevoidadd_edge(int u, int v, int w)// 建边 { edge[++cnt].f = w; edge[cnt].to = v; edge[cnt].nxt = head[u]; head[u] = cnt; return ; }
inlineboolbfs() { memset (deep, -1, sizeof (deep)); queue<int> q; q.push (S); deep[S] = 0; cur[S] = head[S]; while (!q.empty ()) { int u = q.front (); q.pop (); for (int i = head[u]; i; i = edge[i].nxt) { int v = edge[i].to; if (deep[v] == -1 && edge[i].f) { q.push (v); deep[v] = deep[u] + 1; cur[v] = head[v]; if (v == T) returntrue; } } } returnfalse; }
inlineintdfs(int u, int limit) { if (u == T) return limit; int flow = 0; for (int i = cur[u]; i && flow < limit; i = edge[i].nxt) { cur[u] = i; int v = edge[i].to; if (edge[i].f != 0 && deep[v] == deep[u] + 1) { int f = dfs (v, min (edge[i].f, limit - flow)); if (!f) deep[v] = -1; edge[i].f -= f, edge[i ^ 1].f += f; flow += f; } } return flow; }
intdinic() { int maxflow = 0, flow = 0; while (bfs ()) while (flow = dfs (S, N)) maxflow += flow; return maxflow; }
signedmain() { scanf ("%lld %lld %lld", &n, &p, &q); S = 1; T = n * 2 + p + q + 2; // 总共的点数是 n * 2 + p + q + 2 for (int i = 1; i <= n; i ++) // 给 房间 --> 人本体 建边 { for (int j = 1; j <= p; j ++) { scanf ("%lld", &k); if (k == 1) { add_edge (j + 1, 1 + p + i, 1); // 第 i 个人 喜欢 第 j 个房间 add_edge (1 + p + i, j + 1, 0); // 建反向边 } } } for (int i = 1; i <= n; i ++) // 给 人分身 --> 菜 建边 { for (int j = 1; j <= q; j ++) { scanf ("%lld", &k); if (k) { add_edge (1 + p + n + i, 1 + p + n * 2 + j, 1); // 第 i 个人 喜欢 第 j 道菜 add_edge (1 + p + n * 2 + j, 1 + p + n + i, 0); // 建反向边 } } } for (int i = 1; i <= p; i ++) // 给 源点 --> 房间 建边 { add_edge (1, 1 + i, 1); add_edge (1 + i, 1, 0); // 建反向边 } for (int i = 1; i <= q; i ++) // 给 菜 --> 汇点 建边 { add_edge (1 + p + n * 2 + i, 2 + n * 2 + p + q, 1); add_edge (2 + n * 2 + p + q, 1 + p + n * 2 + i, 0); } for (int i = 1; i <= n; i ++) // 给 人本体 --> 人分身 建边 { add_edge (1 + p + i, 1 + p + n + i, 1); // 第 i 个人 喜欢 第 i 个人(你也是屑魔女吗) add_edge (1 + p + n + i, 1 + p + i, 0); // 建反向边 } returncout << dinic (), 0; }
这种建边思想可以利用到别的网络流题目里去。
这边补充一个链式前向星建图的代码:
1 2 3 4 5
inlinevoidadd_edge(int u, int v, int w)// 前向星建边 { edge[++ cnt] = (Edge) {v, head[u], w}; head[u] = cnt; }