[AHOI2009][Mincut 最小割]

判断边是否在某个最小割集中 以及 判断边是否为最小割的必需边。

在残余网络中求出强连通分量,对于不在同一强连通分量且满流的边,必然在某一最小割中。

题目链接

 

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define min(a,b) ( (a)< (b)? (a): (b) )
int const N= 4010, M= 60010;

struct Edge{
	int adj, flow, idx;
	Edge* next;
}tb[M<<1];

int n, m, S, T, cnt;
Edge* mat[N];

inline void add( int u, int v, int idx, int f ){
	++cnt;
	tb[cnt].adj= v; tb[cnt].flow= f; tb[cnt].idx= idx;
	tb[cnt].next= mat[u]; mat[u]= tb+ cnt;
	
	++cnt;
	tb[cnt].adj= u; tb[cnt].flow= 0; tb[cnt].idx= 0;
	tb[cnt].next= mat[v]; mat[v]= tb+ cnt;
}

inline Edge* reserve( Edge* p ){
	return tb+ ( (p- tb)^ 1 ); }

int que[N], head, tail, ht[N];

int bfs(){
	for( int i= 0; i<= n; ++i ) ht[i]= -1;
	que[0]= S; head= tail= 0; ht[S]= 0;
	
	while( head<= tail ){
		int u= que[head++];
		
		for( Edge* p= mat[u]; p; p= p->next )
		if( ht[p->adj]== -1 && p->flow ){
			ht[p->adj]= ht[u]+ 1;
			que[++tail]= p->adj;
		}
	}
	return ht[T]!= -1;
}

int dfs( int u, int flow ){
	if( u== T ) return flow;
	
	int tf= 0, f;
	for( Edge* p= mat[u]; p; p= p->next )
	if( ht[p->adj]== ht[u]+ 1 && p->flow && flow> tf &&
	    ( f= dfs( p->adj, min( p->flow, flow- tf ) ) ) ){
		reserve( p )->flow+= f;
		p->flow-= f;
		tf+= f;
	}
	if( tf== 0 ) ht[u]= -1;
	return tf;
}

int dep[M], low[M], ind[N], stack[N], top, num, id;

void SCC( int u ){
	dep[u]= low[u]= ++num; stack[++top]= u;

	for( Edge* p= mat[u]; p; p= p->next )
	if( p->flow ){
		int v= p->adj;
		
		if( dep[v]== 0  ){
			SCC( v );
			if( low[v]< low[u] ) low[u]= low[v];
		}
		else if( low[v]!= n && dep[v]< low[u] )
		low[u]= low[v];
	}

	if( dep[u]== low[u] ){
		id++;
		do{
			ind[ stack[top] ]= id;
			low[ stack[top] ]= n;
		}while( stack[top--]!= u );
	}
}

void solve(){
	for( int i= 0; i<= n; ++i ){
		dep[i]= 0; low[i]= 0; ind[i]= 0; }
	num= 0; id= 0; top= -1;
	
	for( int i= 1; i<= n; ++i )
	if( dep[i]== 0 ) SCC( i );
	
	for( int i= 0; i<= m; ++i ){
		dep[i]= 0; low[i]= 0; }
	
	for( int u= 1; u<= n; ++u )
	for( Edge* p= mat[u]; p; p= p->next ){
		int v= p->adj;
		
		if( ind[u]!= ind[v] && p->flow== 0 ) dep[p->idx]= 1;
		
		if( ind[u]!= ind[v] && p->flow== 0 &&
		    ind[u]== ind[S] && ind[v]== ind[T] ) low[p->idx]= 1;
	}
	
	for( int i= 1; i<= m; ++i )
	printf("%d %d\n", dep[i], low[i] );
}

int main(){
	while( scanf("%d%d%d%d", &n, &m, &S, &T )!= EOF ){
		cnt= -1;
		for( int i= 0; i<= n; ++i ) mat[i]= 0;
		
		int u, v, d;
		for( int i= 1; i<= m; ++i ){
			scanf("%d%d%d", &u, &v, &d );
			add( u, v, i, d );
		}
		
		int ans= 0;
		while( bfs() ) ans+= dfs( S, 0x7fffffff );

		solve();
	}
	
	return 0;
}
 

 

你可能感兴趣的:(F#)