pku1815 最小割点集 => 拆点 + 最小割

Friendship

这题求得是点连通度,或最小割点集。删除这个集合,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 ;
}

 

你可能感兴趣的:(pku)