CF 976F 递增容量最大流
给你一个二分图 要求你求出对于k=[0~Mindegree] 每个点的度数至少为k所需要的最少边数 并输出方案
如果是单个询问的话 直接跑一个下界网络流即可 但是有多个询问 重建图强行跑不行
反过来考虑,变成至多能删除多少边则建边[s,i,degree[i]-Mindegree] [i,T,degree[i]-Mindegree] [u,v,1]
这样跑出来的流 二分图中没有流量的边代表是要选的 有流量的是要删的 同时保证了每个点的度数不小于Mindegree
则接下来每次对与S,T相连的边容量++ 得到k=[0~Mindegree-1]的答案
#include<bits/stdc++.h> using namespace std; const int MAXN = 4050; const int MAXM = 10005; const int INF = 1000000050; int Head[MAXN], cur[MAXN], lev[MAXN], to[MAXM << 1], nxt[MAXM << 1], f[MAXM << 1], ed = 1, S, T; inline void addedge(int u, int v, int cap) { to[++ed] = v; nxt[ed] = Head[u]; Head[u] = ed; f[ed] = cap; to[++ed] = u; nxt[ed] = Head[v]; Head[v] = ed; f[ed] = 0; return; } inline bool BFS() { int u; memset(lev, -1, sizeof(lev)); queue<int>q; lev[S] = 0; q.push(S); while (q.size()) { u = q.front(); q.pop(); for (int i = Head[u]; i; i = nxt[i]) if (f[i] && lev[to[i]] == -1) { lev[to[i]] = lev[u] + 1; q.push(to[i]); /* if (to[i] == T) { return 1; } magic one way optimize */ } } memcpy(cur, Head, sizeof Head); return lev[T] != -1; } inline int DFS(int u, int maxf) { if (u == T || !maxf) { return maxf; } int cnt = 0; for (int &i = cur[u], tem; i; i = nxt[i]) if (f[i] && lev[to[i]] == lev[u] + 1) { tem = DFS(to[i], min(maxf, f[i])); maxf -= tem; f[i] -= tem; f[i ^ 1] += tem; cnt += tem; if (!maxf) { break; } } if (!cnt) { lev[u] = -1; } return cnt; } int Dinic() { int ans = 0; while (BFS()) { ans += DFS(S, 2147483647); } return ans; } void init(int SS, int TT) { memset(Head, 0, sizeof(Head)); ed = 1; S = SS; T = TT; return; } int du[4005]; int ans[4005][4005]; int main() { int n1, n2, m; int u, v; scanf("%d %d %d", &n1, &n2, &m); int n = n1 + n2; for (int i = 1; i <= m; i++) { scanf("%d %d", &u, &v); addedge(u, v + n1, 1); du[u]++, du[v + n1]++; } int Mindegree = INT_MAX; for (int i = 1; i <= n; i++) { Mindegree = min(Mindegree, du[i]); } S = 0, T = n + 1; for (int i = 1; i <= n1; i++) { addedge(S, i, du[i] - Mindegree); } for (int i = n1 + 1; i <= n; i++) { addedge(i, T, du[i] - Mindegree); } int ansnow = Dinic(); for (int x = 1; x <= n1; x++) { for (int i = Head[x]; i; i = nxt[i]) { v = to[i]; if (v >= n1 + 1 && v <= n) { if (f[i] == 1) { ans[Mindegree][++ans[Mindegree][0]] = i / 2; } } } } for (int i = Head[S]; i; i = nxt[i]) { f[i]++; } for (int x = n1 + 1; x <= n; x++) { for (int i = Head[x]; i; i = nxt[i]) { v = to[i]; if (v == T) { f[i]++; } } } for (int i = Mindegree - 1; i >= 0; i--) { ansnow = Dinic(); for (int x = 1; x <= n1; x++) { for (int j = Head[x]; j; j = nxt[j]) { v = to[j]; if (v >= n1 + 1 && v <= n) { if (f[j] == 1) { ans[i][++ans[i][0]] = j / 2; } } } } for (int j = Head[S]; j; j = nxt[j]) { f[j]++; } for (int x = n1 + 1; x <= n; x++) { for (int j = Head[x]; j; j = nxt[j]) { v = to[j]; if (v == T) { f[j]++; } } } } for (int i = 0; i <= Mindegree; i++) { printf("%d", ans[i][0]); for (int j = 1; j <= ans[i][0]; j++) { printf(" %d", ans[i][j]); } puts(""); } return 0; }