【最大流】HDU 5352 MZL's City
题意:3种操作,加点,加边,删边,然后对于每次加点操作为不超过k个点,求对于每次加点时加点数量的方案的字典序最小。
思路:
要保证字典序最小,就倒着来,能加的都加进去。
建图方法就是拆点,源点向i建流量为k,tot+i到汇点建流量为1,i到tot+v建流量为1.
代码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; typedef long long ll; const int MAX_N = 407; const int MAX_E = MAX_N * MAX_N * 5; const int INF = 0x3f3f3f3f; struct Edge { int v, nxt; ll cap; Edge() { } Edge(int _v, int _nxt, ll _cap) { v = _v, nxt = _nxt, cap = _cap; } }; struct Isap { Edge G[MAX_E]; int edgecnt, head[MAX_N]; int gap[MAX_N], d[MAX_N]; int n, s, t; void init(int n, int s, int t) { this->n = n, this->s = s, this->t = t; edgecnt = 0; memset(head, -1, sizeof head); } void add(int u, int v, ll cap) { G[edgecnt] = Edge(v, head[u], cap); head[u] = edgecnt++; G[edgecnt] = Edge(u, head[v], 0); head[v] = edgecnt++; } ll dfs(int u, ll tot) { if (u == t) return tot; int minh = n - 1; ll leave = tot; for (int i = head[u]; ~i && leave; i = G[i].nxt) { int v = G[i].v; if (G[i].cap > 0) { if (d[v] + 1 == d[u]) { ll c = dfs(v, min(leave, G[i].cap)); G[i].cap -= c; G[i ^ 1].cap += c; leave -= c; if (d[s] >= n) return tot - leave; } minh = min(minh, d[v]); } } if (leave == tot) { --gap[d[u]]; if (gap[d[u]] == 0) d[s] = n; d[u] = minh + 1; ++gap[d[u]]; } return tot - leave; } ll maxFlow() { ll ret = 0; memset(gap, 0, sizeof gap); memset(d, 0, sizeof d); gap[0] = n; while (d[s] < n) { ret += dfs(s, INF); } return ret; } }; int n, m, k; int head[MAX_N], edgecnt; Edge G[MAX_E]; bool dep[507][MAX_N], g[MAX_N][MAX_N]; Isap Flow; int ans[MAX_N]; void Clear() { memset(head, -1, sizeof head); edgecnt = 0; for (int i = 0; i <= m; ++i) for (int j = 0; j <= n; ++j) dep[i][j] = false; for (int i = 0; i <= n; ++i) for (int j = 0; j <= n; ++j) g[i][j] = 0; } void add(int u, int v) { G[edgecnt] = Edge(v, head[u], 0); head[u] = edgecnt++; } void dfs(int id, int u) { add(id, u); dep[id][u] = true; for (int v = 1; v <= n; ++v) { if (!g[u][v] || dep[id][v]) continue; dfs(id, v); } } int cal(int tot) { int s = 0, t = tot + n + 1; Flow.init(tot + n + 2, s, t); for (int i = 1; i <= tot; ++i) Flow.add(s, i, k); for (int i = 1; i <= n; ++i) Flow.add(tot + i, t, 1); ll ret = 0; for (int i = tot; i >= 1; --i) { for (int j = head[i]; ~j; j = G[j].nxt) { int v = G[j].v; Flow.add(i, tot + v, 1); } ret += Flow.maxFlow(); } for (int i = Flow.head[s]; ~i; i = Flow.G[i].nxt) { int v = Flow.G[i].v; ans[v] = Flow.G[i ^ 1].cap; } return ret; } template <class T> inline bool rd(T &ret) { char c; int sgn; if(c = getchar() , c == EOF) return false; while(c != '-' && (c < '0' || c > '9')) c = getchar(); sgn = (c == '-') ? -1 : 1; ret = (c == '-') ? 0 : (c - '0'); while(c = getchar(), c >= '0' && c <= '9') ret = ret * 10 + (c - '0'); ret *= sgn; return true; } int main() { int T; scanf("%d", &T); while (T-- > 0) { Clear(); rd(n), rd(m), rd(k); int tot = 0; for (int i = 1; i <= m; ++i) { int type; rd(type); if (1 == type) { int x; rd(x); dfs(++tot, x); } else if (2 == type) { int u, v; rd(u), rd(v); g[u][v] = g[v][u] = true; } else { int x; rd(x); while (x-- > 0) { int u, v; rd(u), rd(v); g[u][v] = g[v][u] = false; } } } for (int i = 1; i <= tot; ++i) ans[i] = k; int maxFlow = cal(tot); printf("%d\n", maxFlow); for (int i = 1; i <= tot; ++i) printf("%d%c", ans[i], i == tot ? '\n' : ' '); } return 0; }