hdu 3861 The King’s Problem

求单侧连通分量的最小个数。

求强连通分量后,在缩点后的图上用二分图匹配找最小路径覆盖即可。

党写的缩点建图,我的匈牙利。。。

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

using namespace std;
const int MAX = 5010;
const int MAXM = 500000;

struct edge{
	int to;
	struct edge *next;
	void add( int t,struct edge* &b){to=t;next=b;b=this;}
};

edge a[ MAXM*2 ],*biao[MAX],*fan[MAX],*yu[MAX];

int N,M,countt;
int TIME,GROUP;
int flag[MAX];
int label[MAX];
int in[ MAX ];

stack<int> S;
void init( void ){
	for( int i = 1; i <= N; i++ )
		biao[i] = fan[i] = yu[i] = NULL,in[i]=0;
	countt = TIME = GROUP = 0;
}
void dfs1( int u ) {
    flag[u] = 1;    
    for(edge*p=biao[u];p!=NULL;p=p->next){
        if( !flag[p->to] ) dfs1(p->to);
    }
    S.push( u );
} 
void dfs2( int u ,int group) {
    flag[u] = 1;
    for(edge*p=fan[u];p!=NULL;p=p->next){
        if( !flag[p->to] ) dfs2(p->to,group);
    }
    label[u] = group;
}
int total;

int mat[MAX];
bool used[MAX];

int Augment(int x)
{
	int i,k;
	for(edge *p = yu[x]; p != NULL; p = p->next)
	{
		k = p->to;
		if( !used[k] )
		{
			used[k] = 1;
			if( mat[k] == -1 || Augment(mat[k]) )
			{
				mat[k] = x;
				return 1;
			}
		}
	}
	return 0;
}

int Hungary(int s,int n)
{
	memset(mat,-1,sizeof(mat));
	int i,sum = 0;
	for(i=s; i<=n; i++)
	{
		memset(used,0,sizeof(used));
		if( Augment(i) )
			sum++;
	}
	return sum;
}
int main(void){
	int cases,i,j,k,from,to;
	scanf("%d",&cases);
	while( cases-- ){
		scanf("%d%d",&N,&M);
		init();
		for( i = 0; i < M; i++ ){
			scanf("%d%d",&from,&to);
			a[ countt++ ].add( to, biao[from] );
			a[ countt++ ].add( from, fan[to] );
		}
		
		memset( flag,0,sizeof(flag) );
		for( i = 1; i <= N; i++ )
			if( !flag[i] ) dfs1(i);
		
		memset( flag,0,sizeof(flag) );
		while( !S.empty() ){
			int u = S.top();S.pop();
			if( !flag[u] ) dfs2(u,++GROUP);
		}
		
		for( i = 1; i <= N; i++ ){
			for( edge*p=biao[i]; p!=NULL; p=p->next ){
				if( label[i] == label[p->to] ) continue;
				a[countt++].add( label[p->to], yu[ label[i] ] );
				in[ label[p->to] ]++;
			}
		}
		total = 0;
		memset( flag,0,sizeof(flag) );

		total = Hungary(1,GROUP);
		printf("%d\n",GROUP - total);
	}
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值