【HDU】2444 The Accomodation of Students 二分匹配

来源:互联网 发布:电视如何解除网络禁用 编辑:程序博客网 时间:2024/05/20 05:24

传送门:【HDU】2444 The Accomodation of Students


题目分析:能不能分成两个集合主要看这个图是否是一个二分图,我们可以用黑白染色法判定二分图。如果一个点的后继是已经染色的且该后继的颜色和该点相同,说明这个图一定不是二分图,否则判断到所有点都成功染色后,那么该图就是二分图了。由于不知道是否是连通图,所以用并查集得到各个连通块,分别判断是否是二分图。接下来就是二分匹配的事了。


代码如下:


#include <cstdio>#include <cstring>#include <algorithm>using namespace std ;#define REP( i , a , b ) for ( int i = a ; i < b ; ++ i )#define FOR( i , a , b ) for ( int i = a ; i <= b ; ++ i )#define REV( i , a , b ) for ( int i = a ; i >= b ; -- i )#define CLR( a , x ) memset ( a , x , sizeof a )const int MAXN = 205 ;const int MAXQ = 205 ;const int MAXE = 80005 ;const int INF = 0x3f3f3f3f ;struct Edge {int v , n ;Edge () {}Edge ( int v , int n ) : v ( v ) , n ( n ) {}} E[MAXE] ;int H[MAXN] , cntE ;int dx[MAXN] , dy[MAXN] ;int Lx[MAXN] , Ly[MAXN] ;int Q[MAXQ] , head , tail ;int vis[MAXN] ;int dis ;int n , m ;int p[MAXN] ;int color[MAXN] ;void init () {cntE = 0 ;CLR ( H , -1 ) ;}void addedge ( int u , int v ) {E[cntE] = Edge ( v , H[u] ) ;H[u] = cntE ++ ;}int Hopcroft_Karp () {dis = INF ;head = tail = 0 ;CLR ( dx , -1 ) ;CLR ( dy , -1 ) ;FOR ( i , 1 , n )if ( Lx[i] == -1 ) {Q[tail ++] = i ;dx[i] = 0 ;}while ( head != tail ) {int u = Q[head ++] ;if ( dx[u] >= dis )continue ;for ( int i = H[u] ; ~i ; i = E[i].n ) {int v = E[i].v ;if ( dy[v] == -1 ) {dy[v] = dx[u] + 1 ;if ( Ly[v] == -1 )dis = dy[v] ;else {dx[Ly[v]] = dy[v] + 1 ;Q[tail ++] = Ly[v] ;}}}}return dis != INF ;}int hungary ( int u ) {for ( int i = H[u] ; ~i ; i = E[i].n ) {int v = E[i].v ;if ( !vis[v] && dy[v] == dx[u] + 1 ) {vis[v] = 1 ;if ( ~Ly[v] && dy[v] == dis )continue ;if ( Ly[v] == -1 || hungary ( Ly[v] ) ) {Lx[u] = v ;Ly[v] = u ;return 1 ;}}}return 0 ;}int match () {int res = 0 ;CLR ( Lx , -1 ) ;CLR ( Ly , -1 ) ;while ( Hopcroft_Karp () ) {CLR ( vis , 0 ) ;FOR ( i , 1 , n )if ( Lx[i] == -1 )res += hungary ( i ) ;}return res ;}int find ( int x ) {return p[x] == x ? x : ( p[x] = find ( p[x] ) ) ;}int draw () {head = tail = 0 ;CLR ( color , 0 ) ;FOR ( i , 1 , n )if ( find ( i ) == i ) {Q[tail ++] = i ;color[i] = 1 ;}while ( head != tail ) {int u = Q[head ++] ;for ( int i = H[u] ; ~i ; i = E[i].n ) {int v = E[i].v ;if ( !color[v] ) {color[v] = 3 - color[u] ;Q[tail ++] = v ;}if ( color[v] + color[u] != 3 )return 0 ;}}return 1 ;}void solve () {int u , v ;init () ;FOR ( i , 1 , n )p[i] = i ;while ( m -- ) {scanf ( "%d%d" , &u , &v ) ;addedge ( u , v ) ;addedge ( v , u ) ;u = find ( u ) ;v = find ( v ) ;p[u] = v ;}if ( !draw () )printf ( "No\n" ) ;elseprintf ( "%d\n" , match () >> 1 ) ;}int main () {while ( ~scanf ( "%d%d" , &n , &m ) )solve () ;return 0 ;}


0 0
原创粉丝点击