求单侧连通分量的最小个数。
求强连通分量后,在缩点后的图上用二分图匹配找最小路径覆盖即可。
党写的缩点建图,我的匈牙利。。。
#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;
}