题解 P2764 【最小路径覆盖问题】

Ireliaღ

2019-04-14 12:33:09

Solution

**最大流=最小割** ISAP最大流+指针存图 ## 建图 * 把原图每一个节点$i$拆成入点$i$和出点$i + n$,设超级源点为$0$,超级汇点为$n \times 2 + 1$ * 对于$\forall i \in [1, n]$,从$0$向$i$连边,容量$1$ * 对于$\forall i \in [1, n]$,从$i + n$向$n \times 2 + 1$连边,容量$1$ * 对于输入一条边$u \to v$,从$u$向$v + n$连边,容量$1$ ## 输出 我们要找到**没被割掉并且是一条路径起点的点**,然后递归输出这条路径,具体见代码 最终路径数为$n - maxflow$ ## 代码 ```cpp // luogu-judger-enable-o2 #include <queue> #include <cstring> #include <iostream> #include <algorithm> using namespace std; const int MAXN = 65; const int MAXM = 6e3 + 5; const int INF = 0x3f3f3f3f; int n, m; struct Edge{ int to, val; Edge *nxt, *ops; Edge(int to, int val, Edge *nxt): to(to), val(val), nxt(nxt) {} }; namespace ISAP{ Edge *head[MAXN << 1], *cur[MAXN << 1]; int s, t, dep[MAXN << 1], gap[MAXN << 1], res; void AddEdge(int u, int v, int w) { head[u] = new Edge(v, w, head[u]); head[v] = new Edge(u, 0, head[v]); head[v]->ops = head[u]; head[u]->ops = head[v]; } void Bfs() { memset(dep, -1, sizeof(dep)); memset(gap, 0, sizeof(gap)); dep[t] = 0; gap[dep[t]]++; queue<int> q; q.push(t); while (!q.empty()) { int u = q.front(); q.pop(); for (Edge *e = head[u]; e; e = e->nxt) { int v = e->to; if (dep[v] != -1) continue; dep[v] = dep[u] + 1; gap[dep[v]]++; q.push(v); } } } int Dfs(int u, int flow) { if (u == t) { res += flow; return flow; } int used = 0; for (Edge *e = head[u]; e; e = e->nxt) { int v = e->to; if (e->val && dep[v] == dep[u] - 1) { int mi = Dfs(v, min(e->val, flow - used)); if (mi) { e->val -= mi; e->ops->val += mi; used += mi; } if (used == flow) return used; } } gap[dep[u]]--; if (gap[dep[u]] == 0) dep[s] = n * 2 + 3; dep[u]++; gap[dep[u]]++; return used; } void Work() { res = 0; Bfs(); while (dep[s] <= n << 1) Dfs(s, INF); } void Print(int u) {//输出路径 cout << u << ' '; for (Edge *e = head[u]; e; e = e->nxt) { int v = e->to; if (e->val == 0 && v > n && v <= n << 1) { Print(v - n); return; } } } } int main() { ios :: sync_with_stdio(false); cin.tie(NULL); cout.tie(NULL); cin >> n >> m; ISAP :: s = 0; ISAP :: t = n * 2 + 1; for (int i = 1; i <= m; i++) { int x, y; cin >> x >> y; ISAP :: AddEdge(x, y + n, 1); } for (int i = 1; i <= n; i++) { ISAP :: AddEdge(0, i, 1); ISAP :: AddEdge(i + n, n * 2 + 1, 1); } ISAP :: Work(); /*for (Edge *e = ISAP :: head[0]; e; e = e->nxt) { if (e->val == 0) ISAP :: Print(e->to), cout << endl; }*/ //for (int i = 1; i <= n; i++) if (!nots[i]) ISAP :: Print(i), cout << endl; for (int i = 1; i <= n; i++) {//找起点 bool ff = false; for (Edge *e = ISAP :: head[i + n]; e; e = e->nxt) { int v = e->to; if (e->val && v >= 1 && v <= n) { ff = true; break; } } if (!ff) ISAP :: Print(i), cout << endl; } cout << n - ISAP :: res << endl; return 0; } ``` ~~反抄袭自寻~~