题目大意
有 $ ext{N1}$ 本书 $ ext{N2}$本练习册 $ ext{N3}$本答案,一本书只能和一本练习册和一本答案配对。给你一些书和练习册,书和答案的可能的配对关系。问你最多可以配成多少套完整的书册。
解题思路
我已开始直接建立超级源点汇点,然后源点$ ightarrow $练习册连边,练习册$ ightarrow $书连边,书$ ightarrow $答案连边,答案$ ightarrow $汇点连边。然后直接跑 $ ext{Dinic}$。$ ext{RE}$ 了之后 $ ext{TLE}$ 了。后来发现如果「 书 」这个环节不进行拆点的话,会有部分练习册和答案共用一本书。这样就错了。又加了拆点的过程。还是 $ ext{TLE}$。又发现是我的$ ext{Dinic}$ 写的太丑,每次增广只能增广 $1$ 。简直了,又去题解,里找了个写的好看的 $ ext{Dinic}$ 重新搞了一线板子,这才过了这道题。
附上代码
#include <iostream> #include <cstring> #include <cstdio> #include <queue> using namespace std; const int maxn = 8e6+3, INF = 2147483647; int n1, n2, n3, s, t, m, head[maxn], cnt = 1, Depth[maxn], Ans; struct edge { int v, w, nxt; }ed[maxn]; inline int read() { int x = 0, f = 1; char c = getchar(); while (c < '0' || c > '9') {if(c == '-') f = -1; c = getchar();} while (c <= '9' && c >= '0') {x = x*10 + c-'0'; c = getchar();} return x * f; } inline void addedge (int x, int y, int z) { ed[++cnt].nxt = head[x]; ed[cnt].v = y, ed[cnt].w = z; head[x] = cnt; } inline bool bfs() { queue<int> Q; memset(Depth, 0, sizeof(Depth)); Q.push(s), Depth[s] = 1; int u; while (!Q.empty()) { u = Q.front(); Q.pop(); for(int i=head[u]; i; i=ed[i].nxt) { if(ed[i].w > 0 && !Depth[ed[i].v]) { Depth[ed[i].v] = Depth[u] + 1; Q.push(ed[i].v); if(ed[i].v == t) return true; } } } return false; } inline int Dinic(int u, int cap) { if(u == t || !cap) return cap; int delta, ret = 0; for(int i=head[u]; i; i=ed[i].nxt) { if(ed[i].w > 0 && Depth[ed[i].v] == Depth[u] + 1) { delta = Dinic(ed[i].v, min(ed[i].w, cap-ret)); if(delta > 0) { ed[i].w -= delta; ed[i^1].w += delta; ret += delta; } } } return ret; } int main() { n1 = read(), n2 = read(), n3 = read(); s = 0, t = n1*2+n2+n3+1; for(int i=n1*2+1; i<=n1*2+n2; i++) addedge(s, i, 1), addedge(i, s, 0); for(int i=n1*2+n2+1; i<=n1*2+n2+n3; i++) addedge(i, t, 1), addedge(t, i, 0); scanf("%d", &m); int x, y; for(int i=1; i<=m; i++) { scanf("%d%d", &x, &y); addedge(y+n1*2, x, 1), addedge(x, y+n1*2, 0); } scanf("%d", &m); for(int i=1; i<=m; i++) { scanf("%d%d", &x, &y); addedge(x+n1, y+n1*2+n2, 1), addedge(y+n1*2+n2, x+n1, 0); } for(int i=1; i<=n1; i++) { addedge(i, i+n1, 1), addedge(i+n1, i, 0); } while (bfs()) Ans += Dinic(s, INF); printf("%d", Ans); }