hdu 4685 (強聯通 二分匹配 )

先兩邊的點增加至n+m-res, res是原圖的最大匹配,然後做一次完美匹配。新建一個圖G,對於王子匹配的公主向該王子喜歡的其他公主連一條邊,求強連通分量,則王子喜歡的公主並且與王子匹配的公主在同一個強聯通分量裏面都能與王子匹配並且最大匹配數不會減少。 

實際上是王子之間交換各自匹配的公主,如圖


左邊是王子,右邊是公主,紅色是匹配邊,綠色是未匹配邊,藍色是新建的圖 G

因爲原圖不是完美匹配,有些王子公主是單身狗,無法實現上述交換


#include<iostream>
#include<cstring>
#include<string>
#include<cstdio>
#include<stdio.h>
#include<algorithm>
#include<cmath>
#include<set>
#include<map>
#include<queue>
using namespace std;


#define inf 0x3f3f3f3f
#define eps 1e-9
#define mod 10007
#define FOR(i,s,t) for(int i = s; i < t; ++i )
#define REP(i,s,t) for( int i = s; i <= t; ++i )
#define LL unsigned long long
#define ULL unsigned long long
#define pii pair<int,int>
#define MP make_pair
#define lson id << 1 , l , m
#define rson id << 1 | 1 , m + 1 , r 
#define maxn ( 2000+100 )
#define maxe ( 2000000+10 )
#define mxn 20000

vector < int > G[maxn];
int link[maxn], lx[maxn];
bool vis[maxn];

bool dfs1( int u ) {
	for( int i = 0; i < G[u].size(); ++i ) {
		int v = G[u][i];
		if( vis[v] ) continue;
		vis[v] = 1;
		if( link[v] == -1 || dfs1( link[v] ) ) {
			link[v] = u;
			return 1;
		}
	}
	return 0;
}

int hungry( int n ) {
	memset( link, -1, sizeof( link ) );
	int res = 0;
	for( int i = 1; i <= n; ++i ) {
		memset( vis, 0, sizeof( vis ) );
		if( dfs1 ( i ) ) ++res;
	}
	return res;
}

int uN, vN;

int fst[maxn], vv[maxe], nxt[maxe], ec;

void add ( int u, int v ) {
	vv[ec] = v;
	nxt[ec] = fst[u];
	fst[u] = ec++;
}

int sccno[maxn], scc_cnt, S[maxn], stop;
int pre[maxn], low[maxn], dfsc;
void dfs ( int u ) {
	low[u] = pre[u] = ++dfsc;
	S[stop++] = u;
	for( int i = fst[u]; i != -1; i = nxt[i] ) {
		int v = vv[i];
		if( !pre[v] ) {
			dfs( v );
			low[u] = min( low[u], low[v] );
		}
		else if( !sccno[v] ) {
			low[u] = min( low[u], pre[v] );
		}
	}
	if( pre[u] == low[u] ) {
		++scc_cnt;
		while( 1 ) {
			int v = S[--stop];
			sccno[v] = scc_cnt;
			if( v == u ) break;
		}
	}
}

void find_scc( int n ) {
	memset( sccno, 0, sizeof( sccno ) );
	memset( pre, 0, sizeof( pre ) );
	scc_cnt = dfsc = 0;
	stop = 0;
	for( int i = 1; i <= n; ++i ) {
		if( !pre[i] ) dfs( i );
	}
}

vector < int > ans;

int readint () {
	char c;
	int res = 0;
	while( ( c = getchar() ) && ( c < '0' || c > '9' ) ) ;
	res = c - '0';
	while( ( c = getchar() ) && ( '0' <= c && c <= '9' ) ) 
		res = res * 10 + c - '0';
	return res;
}

void out ( int x ) {
	if( x > 9 ) 
		out( x / 10 );
	putchar( x % 10 + '0' );
}

int main () {
	int T, cas = 1;
	scanf("%d", &T ) ;
	while( T-- ) {
		int k, n, m, u, v;
		scanf("%d%d", &n, &m ) ;
		for( int i = 1; i <= n;++i ) {
			G[i].clear();
			k = readint();
			for( int j = 0; j < k; ++j ) {
				v = readint();
				G[i].push_back( v );
			}
		}
		int res = hungry( n );
		vN = uN = n + m - res;
		for( int i = n+1; i <= uN; ++i ) {
		   G[i].clear();	
			for( int j = 1; j <= vN; ++j ) 
				G[i].push_back( j );
		}
		for( int i = 1; i <= uN; ++i )
			for( int j = m + 1;j <= vN; ++j )
				G[i].push_back( j );
		hungry( uN );
		memset( lx, -1, sizeof( lx  ) );
		for( int i = 1; i <= vN; ++i )
			if( link[i] != -1 ) 
				lx[link[i]] = i;
		memset( fst, -1, sizeof( fst ) );
		ec = 0;
		for( int i = 1; i <= uN; ++i ) 
			for( int j = 0; j < G[i].size(); ++j ) 
				if( G[i][j] != lx[i] ) add( lx[i], G[i][j] );
		find_scc( vN );
		printf("Case #%d:\n", cas++ );
		for( int i = 1; i <= n; ++i ) {
			ans.clear();
			for( int j = 0; j < G[i].size(); ++j ) {
				int v = G[i][j];
				if( v > m ) continue;
				if( sccno[v] == sccno[lx[i]] )
					ans.push_back( v );
			}
			sort( ans.begin(), ans.end() );
			out( ans.size() );
			for( int i =0; i < (int)ans.size(); ++i ) 
			{
				putchar( ' ' );
				out( ans[i] );
			}
			printf("\n" );
		}
	}
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章