网络流 二分图匹配,最小路径覆盖

版权声明:本文为博主原创文章,未经博主允许也可以转载。 https://blog.csdn.net/FrankAx/article/details/82763168

洛谷2756飞行员配对
思路:二分图最大匹配。
构图:s -> i , i -> j j -> t 均为1.
Code:

#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
using namespace std;
const int AX = 1e3 + 6 ;
int m , n ; 
int s , t ;
int tot ; 
int cnt ;
int head[AX*20];
int cur[AX*20] ;  
int d[AX];
int idx[AX*20];
struct Node{
	int u , v , flow , next1 ; 
	Node( int u = 0 , int v = 0 , int flow = 0 , int next1 = 0 ):u(u),v(v),flow(flow),next1(next1){}
}G[AX*20];

void addedge( int u , int v , int w ){
	G[tot] = Node( u , v , w , head[u] ) ; head[u] = tot ++ ; 
	G[tot] = Node( v , u , 0 , head[v] ) ; head[v] = tot ++ ; 
}

bool bfs( ){
    memset( d, -1 , sizeof(d) );
    d[s] = 0 ;
    queue<int>q ;
    q.push( s ) ;
    while( !q.empty() ){
        int u = q.front() ; 
        q.pop();
        for( int i = head[u] ; ~i ; i = G[i].next1 ){
            int v = G[i].v ; 
            if( d[v] == -1 && G[i].flow ) {
                d[v] = d[u] + 1 ;
                q.push(v) ;
                if( v == t ) return true ; 
            }
        }
    } 
    return ~d[t];
}

int dfs( int u , int cap ){
    if( u == t ) return cap ; 
    int r = 0 ;
    for( int i = cur[u] ; ~i ; i = G[i].next1) {
        int v = G[i].v ; 
        if( G[i].flow && d[v] == d[u] + 1 ){
            int tmp = min( G[i].flow , cap - r );
            cur[u] = i ;
            tmp = dfs(v,tmp);
            r += tmp ; 
            G[i].flow -= tmp ;
            G[i^1].flow += tmp ; 
            if( r == cap ) break;
        }
    }
    if( !r ) d[u] -= 2 ;
    return r ; 
}

int Dinic( ){
    int cnt = 0 ;
    int tmp ;
    while( bfs() ){
        memcpy(cur,head,sizeof(head));
        while( tmp = dfs( s, INF ) ) cnt += tmp ; 
    }
    return cnt ; 
}


int main(){
	int m , n ; 
	scanf("%d%d",&m,&n);
	int x , y ;
	tot = 0 ;
	memset( head , -1 , sizeof(head) ) ;
	s = n + m + 1 ; 
	t = n + m + 2 ;  
	for( int i = 1 ; i <= m ; i++ ){
		addedge( s , i , 1 ) ;
	}
	for( int i = m + 1 ; i <= n ; i++ ){
		addedge( i , t , 1 ) ;
	}
	int num = 0 ;
	while( scanf("%d%d",&x,&y) && ~x && ~y ){
		addedge( x , y , 1 ) ;
		idx[num++] = tot - 1 ;
	}
	int res = Dinic() ; 
	if( !res ){
		puts("No Solution!");
	}else{
		printf("%d\n",res);
		for( int i = 0 ; i < num ; i++ ){
			if( G[idx[i]].flow ) {
				printf("%d %d\n",G[idx[i]].u,G[idx[i]].v);
			}
		}
	}
	return 0 ; 
}

洛谷2764最小路径覆盖
思路:
每个点拆成 i ,j ,n个点,如果没有边,那么最小路径覆盖就是n条边。每出现一个二分匹配就少一条边。因此最小路径覆盖= 顶点数 - 最大二分匹配。
构图:s - > i , i -> j ,j - > t
最后输出每条简单路时,只需在dfs寻增广路成功时,记录每个点所匹配的点。
Code:

#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
using namespace std ;
const int AX = 6e3 + 66;
int s , t ; 
int head[AX];
int cur[AX] ;
int tot ; 
int d[AX];
int nxt[AX];
int n , m ;   
bool vis[AX];
struct Node{
	int u , v , cap , next1 ;
	Node( int u = 0 , int v = 0 , int cap = 0 , int next1 = 0 ):u(u),v(v),cap(cap),next1(next1){}  
}G[AX*10];

void addedge( int u , int v , int w ){
	G[tot] = Node( u , v , w , head[u] ) ; head[u] = tot ++ ; 
	G[tot] = Node( v , u , 0 , head[v] ) ; head[v] = tot ++ ; 
}

bool bfs( ){
	memset( d , -1 , sizeof(d) ) ;
	d[s] = 0 ; 
	queue<int>q ;
	q.push(s);
	while( !q.empty() ) {
		int u = q.front() ; 
		q.pop() ; 
		for( int i = head[u] ; ~i ; i = G[i].next1 ){
			int v = G[i].v ; 
			if( d[v] == -1 && G[i].cap ){
				d[v] = d[u] + 1 ; 
				q.push(v);
				if( v == t ) return true;
			}
		}
	}return ~d[t];
}

int dfs( int u , int cap ){
	if( u == t || !cap ) return cap ; 
	int r = 0 ;
	for( int i = cur[u] ; ~i ; i = G[i].next1 ){
		int v = G[i].v ;
		if( G[i].cap && d[v] == d[u] + 1 ){
			int tmp = min( G[i].cap , cap - r ) ;
			cur[u] = i ; 
			tmp = dfs( v , tmp );
			if( tmp ){
				nxt[u] = v ; 
				if( v > n ) vis[v-n] = true ;
			}
			r += tmp ; 
			G[i].cap -= tmp ; 
			G[i^1].cap += tmp ; 
			if( r == cap ) break ;
		}
	}
	if( !r ) d[u] -= 2 ; 
	return r ; 
}

int Dinic( ){
	int cnt = 0 ;
	int tmp ; 
	while( bfs( ) ){
		memcpy( cur , head , sizeof(head) );
		while( tmp = dfs( s , INF ) ) cnt += tmp ;
	}
	return cnt ; 
}
int main(){
	int x , y ; 
	memset( head , -1 , sizeof(head) ) ;
	memset( vis , false , sizeof(vis) ) ;
	scanf("%d%d",&n,&m) ;
	s = 2 * n + 1 ; t = 2 * n + 2 ; 
	for( int i = 0 ; i < m ; i++ ){
		scanf("%d%d",&x,&y);
		addedge( x , y + n , 1 ) ;
	}
	for( int i = 1 ; i <= n ; i++ ){
		addedge( s , i , 1 ) ;
	}
	for( int i = 1 ; i <= n ; i++ ){
		addedge( i + n , t , 1 ) ;
	}
	int res = Dinic() ;
	for( int i = 1 ; i <= n ; i++ ){
		if( !vis[i] ){
			printf("%d",i); int u = i ; 
			while( nxt[u] ){
				printf(" %d",nxt[u] - n);
				u = nxt[u] - n; 
			}printf("\n");
		} 
	}
	printf("%d\n",n - res);
	return 0 ; 
}



猜你喜欢

转载自blog.csdn.net/FrankAx/article/details/82763168
今日推荐