这题求得是点连通度,或最小割点集。删除这个集合,S到T就不连通,删除这个集合的任意真子集,S到T仍然有路可走。
做法是拆点,将每个人p拆成两个点p和p',令p' = p + N, 建边<p', p, 1>,1为容量,其余的,如果A有B的号码,建边<A,B',INF>,最后求出S到T'的最大流即可(不同的建边情况不同,这里是S到T')。
还有一难点是如果有多组解,输出score最小的一个,其实就是输出字典序最小的一个。按升序枚举,这个每次删除一个点,删除后,如果流量减少,即为最小割割点,记录一下,如果没有减少,则恢复这个点。当然,如果S和T直接相连,输出NO ANSWER!。
#include < stdio.h >
#include < string .h >
#define INF 0x3fffffff
#define MM 15004
#define NN 404
typedef struct node{
int v, c;
struct node * nxt, * op;
}NODE;
NODE edg[MM];
NODE * Link[NN];
int idx, n, S, T, N;
int h[NN];
int num[NN];
int mark[NN];
int flag[NN][NN];
void Add( int u, int v, int c1, int c2){
idx ++ ;
edg[idx].v = v;
edg[idx].c = c1;
edg[idx].nxt = Link[u];
edg[idx].op = edg + idx + 1 ;
Link[u] = edg + idx;
idx ++ ;
edg[idx].v = u;
edg[idx].c = c2;
edg[idx].nxt = Link[v];
edg[idx].op = edg + idx - 1 ;
Link[v] = edg + idx;
}
int aug( int u, int flow){
int f;
int l = flow;
int tmp = n - 1 ;
if (u == T + N) return flow;
for (NODE * p = Link[u]; p; p = p -> nxt){
if (p -> c && h[u] == h[p -> v] + 1 ){
f = aug(p -> v, p -> c < l ? p -> c : l);
l -= f;
p -> c -= f;
p -> op -> c += f;
if ( ! l || h[S] == n) return flow - l;
}
if (p -> c && h[p -> v] < tmp) tmp = h[p -> v];
}
if (l == flow){
if ( !-- num[h[u]]) h[S] = n;
else ++ num[h[u] = tmp + 1 ];
}
return flow - l;
}
int Sap(){
int ans = 0 ;
n = 2 * N;
memset(h, 0 , sizeof (h));
memset(num, 0 , sizeof (num));
num[ 0 ] = n;
while (h[S] < n){
ans += aug(S, INF);
}
return ans;
}
void CreatGraph(){
int i, j, ii;
idx = 0 ;
memset(Link, 0 , sizeof (Link));
for (i = 1 ; i <= N; i ++ ){
if (mark[i]) continue ;
for (j = 1 ; j <= N; j ++ ){
if (mark[j]) continue ;
if (i != j && flag[i][j]){
ii = i + N;
Add(j, ii, INF, 0 );
}
}
}
for (i = 1 ; i <= N; i ++ ){
if (mark[i]) continue ;
ii = i + N;
Add(ii, i, 1 , 0 );
}
}
int main()
{
int i, j, ans, tmp, t, first;
scanf( " %d%d%d " , & N, & S, & T);
for (i = 1 ; i <= N; i ++ ){
for (j = 1 ; j <= N; j ++ ){
scanf( " %d " , & flag[i][j]);
}
}
if (flag[S][T] == 1 ){
puts( " NO ANSWER! " );
return 0 ;
}
memset(mark, 0 , sizeof (mark));
CreatGraph();
ans = Sap();
tmp = ans;
if (ans == 0 ){
puts( " 0 " );
return 0 ;
}
for (i = 1 ; i <= N; i ++ ){
if (i == S || i == T) continue ;
mark[i] = 1 ;
CreatGraph();
t = Sap();
if (t < tmp){
tmp = t;
} else {
mark[i] = 0 ;
}
}
printf( " %d\n " , ans);
first = 1 ;
for (i = 1 ; i <= N; i ++ ){
if (mark[i])
if (first){
first = 0 ;
printf( " %d " , i);
}
else printf( " %d " , i);
}
puts( "" );
return 0 ;
}