题目大意:求一个有向图删除多少的点,使得源点到终点不连通
解题思路:最大流,拆点和枚举
每个点拆成两个点,这两个点之间的容量为1,源点和终点拆成的点容量为无穷大,
当一个点和另一个点有边时,假设是i和j两个点, 那么i拆成两个点i, i',j拆成两个点j, j', i'和j连接,容量为无穷大
然后枚举除源点,和终点的每个点,删除这个点,看容量是否减少,减少则为要删除的点。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <climits>
#include <queue>
using namespace std;
const int maxn = 210;
const int maxm = 10010;
struct node
{
int u, v, cap, flow, next;
};
int n, e, s, t, tot, graph[maxn][maxn], head[2 * maxn], cur[2 * maxn], height[2 * maxn], cnt[2 * maxn], store[2 * maxn], path[2 * maxn];
int tt[2][maxn];
node edge[maxm + 4 * maxn];
void addEdge(int u, int v, int val);
int sap();
void build();
int main()
{
while(scanf("%d %d %d", &n, &s, &t) != EOF)
{
s--; t--;
bool flag = false;
for(int i = 0; i < n; i++)
{
for(int j = 0; j < n; j++)
scanf("%d", &graph[i][j]);
}
if(graph[s][t] == 1)
{
printf("NO ANSWER!\n");
continue;
}
build();
int ans = sap();
printf("%d\n", ans);
if(ans == 0)
continue;
for(int i = 0; i < n; i++)
{
if(i == s || i == t)
continue;
for(int j = 0; j < n; j++)
{
tt[0][j] = graph[i][j];
tt[1][j] = graph[j][i];
graph[i][j] = 0;
graph[j][i] = 0;
}
build();
int tmp = sap();
if(tmp < ans)
{
ans--;
printf("%d ", i + 1);
}
else
{
for(int j = 0; j < n; j++)
{
graph[i][j] = tt[0][j];
graph[j][i] = tt[1][j];
}
}
if(tmp == 0)
break;
}
printf("\n");
}
return 0;
}
void addEdge(int u, int v, int val)
{
edge[e].u = u;
edge[e].v = v;
edge[e].cap = val;
edge[e].flow = 0;
edge[e].next = head[u];
head[u] = e++;
edge[e].u = v;
edge[e].v = u;
edge[e].cap = 0;
edge[e].flow = 0;
edge[e].next = head[v];
head[v] = e++;
}
void build()
{
memset(head, -1, sizeof(head));
e = 0;
for(int i = 0; i < n; i++)
{
for(int j = 0; j < n; j++)
{
if(i == j)
{
if(i == s || i == t)
addEdge(i, i + n, INT_MAX);
else
addEdge(i, i + n, 1);
}
else if(graph[i][j] == 1)
addEdge(i + n, j, INT_MAX);
}
}
}
int sap()
{
int ans = 0, u, v, now;
memset(height, 0, sizeof(height));
memset(cnt, 0, sizeof(cnt));
cnt[0] = 2 * n;
for(int i = 0; i < 2 * n; i++)
cur[i] = head[i];
store[s] = INT_MAX;
u = s;
while(height[s] < 2 * n)
{
for(now = cur[u]; now != -1; now = edge[now].next)
{
v = edge[now].v;
if(edge[now].cap != edge[now].flow && height[u] == height[v] + 1)
break;
}
if(now != -1)
{
cur[u] = now;
path[v] = now;
store[v] = min(store[u], edge[now].cap - edge[now].flow);
u = v;
if(u == t)
{
while(u != s)
{
edge[path[u]].flow += store[t];
edge[path[u] ^ 1].flow -= store[t];
u = edge[path[u]].u;
}
ans += store[t];
store[s] = INT_MAX;
}
}
else
{
if(--cnt[height[u]] == 0)
break;
height[u] = 2 * n;
cur[u] = head[u];
for(now = head[u]; now != -1; now = edge[now].next)
{
v = edge[now].v;
if(edge[now].cap > edge[now].flow && height[u] > height[v] + 1)
height[u] = height[v] + 1;
}
cnt[height[u]]++;
if(u != s)
u = edge[path[u]].u;
}
}
return ans;
}