USACO 5.4.3 点的最小割
这道题的难点在于将点拆分, 无向图变为有向图, 对于 i点我们可以将这个点拆分成2*i-1 -> 2*i,权值为1 对于i - j, 我们可以将点拆分以后再添加2*j -> 2*i-1 2*i -> 2*j-1,权值为inf, 然后求解最大流即为要去掉的顶点的个数, 求解具体的边的时候我们可以枚举要删除的边, 假设删除前的最大流为f,边权为1, 删除边后的最大流为ff, 若ff+1 == f的话那么这条边就在最小割集中。然后更新最大流,删掉最这条边重复上述操作即可, 代码如下:
/* ID: m1500293 LANG: C++ PROG: telecow */ #include <cstdio> #include <cstring> #include <algorithm> #include <queue> using namespace std; const int maxn = 250; int inf = 0x3f3f3f3f; struct Dinic { int n; //n个顶点 struct edge { int from, to, cap; }; vector<int> G[maxn]; vector<edge> e; int level[maxn], iter[maxn]; void init() { for(int i=0; i<=n; i++) G[i].clear(); e.clear(); } void add_edge(int u, int v, int cap) { e.push_back((edge){u, v, cap}); e.push_back((edge){v, u, 0}); int m = e.size(); G[u].push_back(m-2); G[v].push_back(m-1); } void bfs(int s) { memset(level, -1, sizeof(level)); queue<int> que; level[s] = 0; que.push(s); while(!que.empty()) { int u = que.front(); que.pop(); for(int i=0; i<G[u].size(); i++) { edge &te = e[G[u][i]]; if(te.cap>0 && level[te.to]<0) { level[te.to] = level[u] + 1; que.push(te.to); } } } } int dfs(int v, int t, int f) { if(v == t) return f; for(int &i=iter[v]; i<G[v].size(); i++) { edge &tpe = e[G[v][i]]; if(tpe.cap>0 && level[v]<level[tpe.to]) { int d = dfs(tpe.to, t, min(f, tpe.cap)); if(d > 0) { tpe.cap -= d; e[G[v][i]^1].cap += d; return d; } } } return 0; } int max_flow(int s, int t) { int flow = 0; for(;;) { bfs(s); if(level[t]<0) return flow; memset(iter, 0, sizeof(iter)); int f; while((f=dfs(s, t, 0x3fffffff)>0)) flow += f; } } }aa, bb; bool cmp(const int &a, const int &b) { return a < b; } int ans[200], nans; int main() { freopen("telecow.in", "r", stdin); freopen("telecow.out", "w", stdout); int N, M, c1, c2; scanf("%d%d%d%d", &N, &M, &c1, &c2); aa.n = 2*N; aa.init(); for(int i=0; i<M; i++) { int u, v; scanf("%d%d", &u, &v); aa.add_edge(2*u, 2*v-1, inf); aa.add_edge(2*v, 2*u-1, inf); // aa.add_edge(2*u-1, 2*u, 1); // aa.add_edge(2*v-1, 2*v, 1); //会导致重复添加一条边 } for(int i=1; i<=N; i++) aa.add_edge(2*i-1, 2*i, 1); //printf("%d\n", aa.max_flow(2*c1, 2*c2-1)); bb = aa; int f = bb.max_flow(2*c1, 2*c2-1); int ans1 = f; nans = 0; for(int i=0; i<aa.e.size(); i++) if(aa.e[i].cap == 1) { bb = aa; bb.e[i].cap = 0; int ff = bb.max_flow(2*c1, 2*c2-1); if(ff+1 == f) //这条边在最小割中 { ans[nans++] = bb.e[i].to/2; f -= 1; //更新最大流 aa.e[i].cap = 0; //删掉这条边 } } sort(ans, ans+nans, cmp); printf("%d\n", ans1); for(int i=0; i<nans; i++) printf("%d%c", ans[i], i==nans-1?'\n':' '); return 0; }