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