POJ_1815
对于问至少删掉几个点使得S、T不联通,可以将每个点拆成i、i'两个点并连一条容量为1的i->i'的边,将其他关系依次补全后求最小割即可。
但是这个题目要求输出字典序最小的结果,那么就需要依次枚举每个点,如果删掉这个点之后最小割变小了,那么就说明这个点是最小割中的点,将其删除,否则就说名这个点不是最小割中的点,将其恢复。然后重复上面的操作就可以得到字典序最小的序列了。
#include<stdio.h> #include<string.h> #include<algorithm> #define MAXN 210 #define MAXD 420 #define MAXM 80410 #define INF 0x3f3f3f3f int N, S, T, first[MAXD], e, next[MAXM], v[MAXM], flow[MAXM], g[MAXN][MAXN]; int d[MAXD], q[MAXD], work[MAXD], del[MAXN], list[MAXN], L; void add(int x, int y, int z) { v[e] = y, flow[e] = z; next[e] = first[x], first[x] = e ++; } void build() { int i, j; memset(first, -1, sizeof(first[0]) * (N + 1) * 2); e = 0; for(i = 1; i <= N; i ++) for(j = i + 1; j <= N; j ++) if(g[i][j]) { add(i << 1 | 1, j << 1, INF), add(j << 1, i << 1 | 1, 0); add(j << 1 | 1, i << 1, INF), add(i << 1, j << 1 | 1, 0); } for(i = 1; i <= N; i ++) if(!del[i]) add(i << 1, i << 1 | 1, 1), add(i << 1 | 1, i << 1, 0); } void init() { int i, j, k; for(i = 1; i <= N; i ++) for(j = 1; j <= N; j ++) scanf("%d", &g[i][j]); } int bfs() { int i, j, rear = 0; memset(d, -1, sizeof(d[0]) * (N + 1) * 2); d[S << 1 | 1] = 0, q[rear ++] = S << 1 | 1; for(i = 0; i < rear; i ++) for(j = first[q[i]]; j != -1; j = next[j]) if(flow[j] && d[v[j]] == -1) { d[v[j]] = d[q[i]] + 1, q[rear ++] = v[j]; if(v[j] == T << 1) return 1; } return 0; } int dfs(int cur, int a) { if(cur == T << 1) return a; for(int &i = work[cur]; i != -1; i = next[i]) if(flow[i] && d[v[i]] == d[cur] + 1) if(int t = dfs(v[i], std::min(flow[i], a))) { flow[i] -= t, flow[i ^ 1] += t; return t; } return 0; } int dinic() { int ans = 0, t; while(bfs()) { memcpy(work, first, sizeof(first[0]) * (N + 1) * 2); while(t = dfs(S << 1 | 1, INF)) ans += t; } return ans; } void solve() { int i, j, k, pre; if(g[S][T]) { printf("NO ANSWER!\n"); return ; } memset(del, 0, sizeof(del[0]) * (N + 1)); build(); L = pre = dinic(); for(i = 1, j = 0; i <= N && j < L; i ++) if(i != S && i != T) { del[i] = 1; build(); if((k = dinic()) < pre) pre = k, list[j ++] = i; else del[i] = 0; } printf("%d\n", L); if(L) { printf("%d", list[0]); for(i = 1; i < L; i ++) printf(" %d", list[i]); printf("\n"); } } int main() { while(scanf("%d%d%d", &N, &S, &T) == 3) { init(); solve(); } return 0; }