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" );
		}
	}
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值