一.原题链接:http://poj.org/problem?id=1815
二.题目大意:给你一个不带权连通图,第一行为节点数,起点,终点。然后给你一个邻接矩阵,描述点与点之间的关系。按字典序输出最小点割集。最小点割集如果有多个,按字典序最小那个输出。
三.解题思路:所谓最小点割集,就是问图中去掉多少个点就可以使得源点和汇点不联通。(本题中源点汇点不可去掉)
最小点割集求解方法:
1.有向图:把一个点拆成(i, i+N)2个点,之间容量为1。如果i, j2个点在原图中联通,则将i+N,j相连,容量为无穷大。然后求最小割,可见被最小割割到的都是容量是1的边,(如果割到一条INF,说明没有最小点割集。)而且那些边必将连着i,i+N,于是i就是被割的点。
2.无向图:把一个点拆成(i, i+N)2个点,之间容量为1。如果i, j2个点在原图中联通,则将i+N,j相连,容量为无穷大。则将j, i+N相连,容量为无穷大。以下如上。
本题思路:枚举每一个顶点,除了S和T之外,然后求最大流,看看去掉这个顶点和没去掉有没有影响。(最大流变小),要从小到大枚举。
四,代码
#include <iostream> #include <cstdio> #include <queue> #include <cstring> #include <cstdlib> using namespace std; const int INF = 0x3f3f3f3f, MAX_N = 409; class Dinic { public: struct Edge { int v, w, next; }; int cnt, head[MAX_N], dist[MAX_N], s, t; Edge edges[MAX_N*MAX_N]; void init(int is, int it) { cnt = 0; s = is, t = it; memset(head, -1, sizeof(head)); } void addEdge(int u, int v, int weight) { edges[cnt] = (Edge){v, weight, head[u]}; head[u] = cnt++; edges[cnt] = (Edge){u, 0, head[v]}; head[v] = cnt++; } bool BFS() { int i, cur; queue <int> que; que.push(s); memset(dist, -1, sizeof(dist)); dist[s] = 0; while(!que.empty()){ cur = que.front(); que.pop(); for(i = head[cur]; i != -1; i = edges[i].next) if(-1 == dist[edges[i].v] && edges[i].w){ dist[edges[i].v] = dist[cur] + 1; que.push(edges[i].v); } } return dist[t] != -1; } int DFS(int start, int curFlow) { if(start == t) return curFlow; int i, minFlow = 0, v, temp; for(i = head[start]; i != -1; i = edges[i].next){ v = edges[i].v; if(dist[start] == dist[v] - 1 && edges[i].w > 0){ temp = DFS(v, min(edges[i].w, curFlow)); edges[i].w -= temp; edges[i^1].w += temp; curFlow -= temp; minFlow += temp; if(0 == curFlow) break; } } return minFlow; } int maxFlow() { int res = 0; while(BFS()){ res += DFS(s, INF); } return res; } }; int S, T, N, mp[MAX_N][MAX_N], saveMap1[MAX_N], saveMap2[MAX_N]; int buildGraph() { int i, j; Dinic G; G.init(S+N, T); for(i = 1; i <= N; i++) G.addEdge(i, i + N, 1); for(i = 1; i <= N; i++) for(j = 1; j <= N; j++) if(i != j && 1 == mp[i][j]) G.addEdge(i + N, j, INF); return G.maxFlow(); } int main() { //freopen("in.txt", "r", stdin); int i, j, maxFlow, res[MAX_N], cnt, temp; scanf("%d%d%d", &N, &S, &T); for(i = 1; i <= N; i++) for(j = 1; j <= N; j++) scanf("%d", &mp[i][j]); if(1 == mp[S][T]){ printf("NO ANSWER!\n"); return 0; } maxFlow = buildGraph(); cnt = 0; for(i = 1; i <= N; i++){ if(i == S || i == T) continue; for(j = 1; j <= N; j++){ saveMap1[j] = mp[i][j]; saveMap2[j] = mp[j][i]; mp[i][j] = mp[j][i] = 0; } temp = buildGraph(); if(maxFlow > temp){ res[cnt++] = i; maxFlow--; } else{ for(j = 1; j <= N; j++){ mp[i][j] = saveMap1[j]; mp[j][i] = saveMap2[j]; } } if(0 == maxFlow) break; } printf("%d\n", cnt); for(i = 0; i < cnt; i++) printf("%d ", res[i]); return 0; }