最小割
建图: 每一个点u都增加一个虚点 $u\prime$ , u 和 $u\prime$之间连一条边,容量为1, 如果要删除点u,那么只要断u和$u\prime$之间的边就行。 如果u和v之间有联系,从 $u\prime$向v连一条边,容量为INF。因为s和t不会被删除,所以这两个点与他们对应的虚点的容量为INF,而不是1,为了避免被割掉。最后增加一个源点和汇点,容量为INF。
最小割的结果就是题目要求的个数
为了保证输出删掉的点是字典序最小的,我们需要一个个枚举点,删除这个点的情况下再重建一次图,跑一次dinic,如果答案比之前的小,那么这个点就是我们需要的,否则要把这个点还原回去。
g++ 的顶点数要开很大,这里开了1000,c++ 500就够
#include <iostream>
#include <cstdio>
#include <cstring>
#include <map>
#include <vector>
#include <cmath>
#include <algorithm>
#include <queue>
#include <stack>
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const int Maxn = 1000+10;
const int INF = 0x3f3f3f3f;
const long long LINF = 1e18;
struct Edge {
int v, cap, flow, next;
} edge[Maxn*Maxn*4];
int deep[Maxn], qu[Maxn], indx[Maxn], h[Maxn], edge_cnt, N;
int G[Maxn][Maxn];
bool node[Maxn];
void add(int u, int v, int c) {
edge[edge_cnt].v = v;
edge[edge_cnt].cap = c;
edge[edge_cnt].flow = 0;
edge[edge_cnt].next = h[u];
h[u] = edge_cnt++;
edge[edge_cnt].v = u;
edge[edge_cnt].cap = 0;
edge[edge_cnt].flow = 0;
edge[edge_cnt].next = h[v];
h[v] = edge_cnt++;
}
bool bfs(int s, int t) {
int head = 0, tail = 0;
memset(deep, 0, sizeof(deep));
deep[s] = 1; qu[tail++] = s;
while(head < tail) {
int u = qu[head++];
for(int i = h[u]; i != -2; i = edge[i].next) {
Edge &e = edge[i];
if(deep[e.v] == 0 && e.cap > e.flow) {
deep[e.v] = deep[u]+1;
qu[tail++] = e.v;
}
}
}
if(deep[t] > 0) return true;
else return false;
}
int dfs(int cur, int t, int a) {
if(cur == t || a == 0) return a;
if(indx[cur] == -1) indx[cur] = h[cur];
int flow = 0, f;
for(int &i = indx[cur]; i != -2; i = edge[i].next) {
Edge &e = edge[i];
if(deep[e.v] == deep[cur]+1) {
f = dfs(e.v, t, min(a, e.cap-e.flow));
if(f > 0) {
e.flow += f;
edge[i^1].flow -= f;
flow += f;
a -= f;
if(a == 0) break;
}
}
}
return flow;
}
int dinic(int s, int t) {
int ans = 0;
while(bfs(s, t)) {
memset(indx, -1, sizeof(indx));
ans += dfs(s, t, INF);
}
return ans;
}
void build(int s, int t) {
for(int i = 0; i <= 3*N; ++i) h[i] = -2;
edge_cnt = 0;
add(0, s, INF);
add(t, 2*N+1, INF);
for(int i = 1; i <= N; ++i) {
if(!node[i]) continue;
if(i == s || i == t) add(i, N+i, INF);
else add(i, N+i, 1);
}
for(int u = 1; u <= N; ++u) {
for(int v = 1; v <= N; ++v) {
if(G[u][v] == 1) {
add(N+u, v, INF);
}
}
}
}
int main(void)
{
int s, t;
scanf("%d%d%d", &N, &s, &t);
for(int i = 1; i <= N; ++i) {
for(int j = 1; j <= N; ++j) scanf("%d", &G[i][j]);
}
memset(node, true, sizeof(node));
build(s, t);
int sum = dinic(0, 2*N+1);
if(G[s][t] == 1) printf("NO ANSWER!\n");
else {
printf("%d\n", sum);
int tmp;
if(sum != 0) {
for(int i = 1; i <= N; ++i) {
if(i == s || i == t) continue;
node[i] = false;
build(s, t);
tmp = dinic(0, 2*N+1);
if(tmp < sum) {
sum = tmp;
printf("%d", i);
if(sum <= 0) break;
else printf(" ");
} else node[i] = true;
}
puts("");
}
}
return 0;
}
浙公网安备 33010602011771号