题目大意
给一幅由N个点和M条无向边组成的图,要求删掉最少的点使得c1和c2无法连通(不能删这两个点)。输出删的点数以及要删的点,要求删的点的字典序最小。
题解
我记得以前貌似是删边的。删点其实也类似,把点转换成边就可以了。所以就要拆点了,拆点的方法不多说。
然后跑一遍最小割(最大流),原来的边的流量设为无限大,拆点的边就置为1,不过要注意的是这里是无向边。
主要问题就是怎么让答案的字典序最小。其实枚举就行了!枚举每一个点,然后删点,跑最大流,看一下流量是否变小,变小了就真(是真的!)删掉这个点,如果没有改变说明删不删这个点都一样。
因为每次增广都肯定会少掉至少一条边(点),这里的求最大流速度就会很快,大概是O(N2),那么总的时间复杂度就是O(N3)。
代码
/* TASK:telecow LANG:C++ */ #include <cstdio> #include <cstring> #include <queue> using namespace std; const int INF = 0x7fffffff; struct Edge { int c, f; bool canget; Edge() { canget = false; } Edge(int cap, int flow) : c(cap), f(flow) { canget = true; } }net[205][205]; int n, m, c1, c2, netflow, d[205], side[605][2]; bool BFS() { memset(d, 0, sizeof(d)); d[2 * c1] = 1; queue<int> Q; Q.push(2 * c1); while (!Q.empty()) { int x = Q.front(); Q.pop(); for (int i = 1; i <= 2 * n; ++i) if (d[i] == 0 && net[x][i].canget && net[x][i].f < net[x][i].c) { d[i] = d[x] + 1; Q.push(i); } } return d[2 * c2 - 1]; } int DFS(int x, int a) { if (x == 2 * c2 - 1 || a == 0) return a; int flow = 0; for (int i = 1; i <= 2 * n; ++i) { int fw; if (d[x] + 1 == d[i] && (fw = DFS(i, min(a, net[x][i].c - net[x][i].f))) > 0) { net[x][i].f += fw; net[i][x].f -= fw; flow += fw; a -= fw; } if (a == 0) break; } return flow; } int main() { freopen("telecow.in", "r", stdin); freopen("telecow.out", "w", stdout); scanf("%d%d%d%d", &n, &m, &c1, &c2); for (int i = 1; i <= n; ++i) { net[2 * i - 1][2 * i] = Edge(1, 0); net[2 * i][2 * i - 1] = Edge(0, -1); } for (int i = 0; i < m; ++i) { int a, b; scanf("%d%d", &a, &b); side[i][0] = a; side[i][1] = b; net[2 * a][2 * b - 1] = Edge(INF, 0); net[2 * b - 1][2 * a] = Edge(0, 0); net[2 * b][2 * a - 1] = Edge(INF, 0); net[2 * a - 1][2 * b] = Edge(0, 0); } netflow = 0; net[2 * c1 - 1][2 * c1].canget = net[2 * c1][2 * c1 - 1].canget = false; net[2 * c2 - 1][2 * c2].canget = net[2 * c2][2 * c2 - 1].canget = false; while (BFS()) { netflow += DFS(2 * c1, INF); } printf("%d ", netflow); for (int k = 1; k <= n; ++k) { if (k == c1 || k == c2) continue; for (int i = 1; i <= n; ++i) if (net[2 * i - 1][2 * i].canget){ net[2 * i - 1][2 * i] = Edge(1, 0); net[2 * i][2 * i - 1] = Edge(0, -1); } net[2 * k - 1][2 * k].canget = net[2 * k][2 * k - 1].canget = false; for (int i = 0; i < m; ++i) { int a = side[i][0], b = side[i][1]; net[2 * a][2 * b - 1] = Edge(INF, 0); net[2 * b - 1][2 * a] = Edge(0, 0); net[2 * b][2 * a - 1] = Edge(INF, 0); net[2 * a - 1][2 * b] = Edge(0, 0); } int sumflow = 0; while (BFS()) { sumflow += DFS(2 * c1, INF); } if (sumflow < netflow) { netflow = sumflow; printf("%d", k); if (netflow == 0) break; else printf(" "); } else { net[2 * k - 1][2 * k].canget = net[2 * k][2 * k - 1].canget = true; } } printf(" "); return 0; }