P9409 题解

· · 题解

题意回顾

求出初始时最多的玩偶总数。 $ 1 \le tn,tm \le 3 \times 10^4 $。 ## 分析 可以理解为,这是一个分层图,有 $ t+1 $ 层,第 $ i $ 层的 $ u $ 和第 $ i+1 $ 层的 $ v $ 存在一条有向边当且仅当第 $ i $ 天的座位图 $ u,v $ 存在连边。这 $ t+1 $ 层中的每个结点**限流** $ 1 $ 个玩偶。 **限流**怎么实现:将这个点拆成 $ u_1,u_2 $,入边连向 $ u_1 $,$ u_2 $ 连出出边,$ u_1,u_2 $ 连一条有向边,边限流为 $ 1 $,这样就把点限流转化为边限流了。 考虑初始时,玩偶是由『老师』分发的,由『老师』结点 $ 0 $ 向所有 $ 1 $ 层结点连有向边;最后,统计玩偶的总数,可以由所有 $ t+1 $ 层结点向『统计』结点连有向边。 此时,转化为『老师』向『统计』通过图上的边**最多**能传输多少个玩偶,有些边有一些限流,这不就是一个**图的有源汇最大流问题**吗?使用 Dinic 算法解决。 ## AC 代码 ```cpp #include <iostream> #include <cstdio> #include <algorithm> #include <vector> #include <cstring> #include <queue> using namespace std; const int N = 5e5 + 5; int t, n; int m; struct node { int v; int w; }; int wei[N]; int cm = 0; vector<node> g[N]; inline int Id(int x, int typ, int y) { return (x * 2 + typ - 3) * n + y; } void add(int u, int v, int zx, int fx) { g[u].push_back((node){v, cm}); wei[cm++] = zx; g[v].push_back((node){u, cm}); wei[cm++] = fx; } int dep[N]; int cur[N]; bool bfs(int from, int to) { memset(dep, 0, sizeof(dep)); dep[from] = 1; queue<int> que; que.push(from); while(!que.empty()) { int u = que.front(); que.pop(); for(int i = 0; i < g[u].size(); i++) { int v = g[u][i].v; int w = g[u][i].w; if(dep[v] || !wei[w]) continue; dep[v] = dep[u] + 1, que.push(v); } } return dep[to]; } int dfs(int u, int to, int lim) { int down = 0; if(u == to) return lim; for(int i = cur[u]; i < g[u].size(); i++) { cur[u] = i; int v = g[u][i].v; int w = g[u][i].w; if(dep[v] != dep[u] + 1 || !wei[w]) continue; int ls = dfs(v, to, min(wei[w], lim - down)); if(!ls) dep[v] = 0; wei[w] -= ls, wei[w ^ 1] += ls, down += ls; if(down == lim) break; } return down; } int Dinic(int from, int to) { int res = 0; while(bfs(from, to)) { memset(cur, 0, sizeof(cur)); res += dfs(from, to, 1e9 + 5); } return res; } int main() { cin >> t >> n; for(int i = 1; i <= n; i++) add(0, i, 1, 0); for(int dy = 1; dy <= t; dy++) { cin >> m; int u, v; for(int i = 1; i <= m; i++) { cin >> u >> v; add(Id(dy, 1, u), Id(dy, 2, v), 88, 0); add(Id(dy, 1, v), Id(dy, 2, u), 88, 0); } for(int i = 1; i <= n; i++) add(Id(dy, 2, i), Id(dy + 1, 1, i), 1, 0); } int gzh = Id(t + 1, 1, 1); for(int i = 1; i <= n; i++) add(Id(t, 2, i), gzh, 1, 0); cout << Dinic(0, gzh) << endl; return 0; } ```