一.原题链接: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;
}