第二次世界大战时期,英国皇家空军从沦陷国征募了大量外籍飞行员。由皇家空军派出的每一架飞机都需要配备在航行技能和语言上能互相配合的 2 名飞行员,其中 1 名是英国飞行员,另 1 名是外籍飞行员。在众多的飞行员中,每一名外籍飞行员都可以与其他若干名英国飞行员很好地配合。如何选择配对飞行的飞行员才能使一次派出最多的飞机。对于给定的外籍飞行员与英国飞行员的配合情况,试设计一个算法找出最佳飞行员配对方案,使皇家空军一次能派出最多的飞机。
对于给定的外籍飞行员与英国飞行员的配合情况,编程找出一个最佳飞行员配对方案,使皇家空军一次能派出最多的飞机。
输入描述 Input Description
第 1 行有 2 个正整数 m和 n。n 是皇家空军的飞行员总数(n<100);m 是外籍飞行员数。外籍飞行员编号为 1~m;英国飞行员编号为 m+1~n。接下来每行有 2 个正整数 i 和 j,表示外籍飞行员 i 可以和英国飞行员 j 配合。文件最后以 2个-1 结束。
输出描述 Output Description
第 1 行是最佳飞行员配对方案一次能派出的最多的飞机数 M。接下来 M 行是最佳飞行员配对方案。每行有 2个正整数 i 和 j,表示在最佳飞行员配对方案中,飞行员 i 和飞行员 j 配对。如果所求的最佳飞行员配对方案不存在,则输出‘No Solution!’。
样例输入 Sample Input
5 10
1 7
1 8
2 6
2 9
2 10
3 7
3 8
4 7
4 8
5 10
-1 -1
样例输出 Sample Output
4
1 7
2 9
3 8
5 10
#include <algorithm> #include <iostream> #include <cstdlib> #include <cstring> #include <cstdio> #include <queue> using namespace std ; const int inf = 1<<30 , maxn = 10000 + 11 ; int m , n , head[1003] , cnt , dis[1001] , s , t , cur[1001] , sum ; struct id { int nxt , to , vi , fro; }edge[maxn<<1] ; struct A { int a , b ; } ans[1001] ; queue< int > Q ; void add( int a , int b , int c ) { edge[++cnt].nxt = head[a] , edge[cnt].to = b ; edge[cnt].vi = c , head[a] = cnt ; edge[cnt].fro = a ; } int read( ) { char ch = getchar( ) ; int k = 1 , ret = 0 ; while( ch < '0' || ch > '9' ) { if( ch == '-' ) k = -1 ; ch = getchar( ) ; } while( ch >= '0' && ch <='9' ) ret = ret * 10 + ch - '0' , ch = getchar( ) ; return ret * k ; } void input( ) { m = read( ) , n = read( ) ; int a, b ; cnt = 1 ; s = 100<<2 , t = 100<<2 + 1 ; memset( head , -1 , sizeof(head)) ; while( 1 ) { a = read( ) , b = read( ) ; if( a == -1 && b == -1 ) break ; add( a , b , 1 ) ; add( b , a , 0 ) ; } for( int x = 1 ; x <= m ; x++ ) { add( s , x , 1 ) ; add( x , s , 0 ) ; } for( int x = m + 1 ; x <= n ; ++x ) { add( x , t , 1 ) ; add( t , x , 0 ) ; } } bool bfs( ) { memset( dis , -1 , sizeof(dis) ) ; Q.push( s ) ; dis[s] = 0 ; while( !Q.empty( ) ) { int u = Q.front( ) ; Q.pop( ) ; for( int i = head[u] ; ~i ; i = edge[i].nxt ) { int v = edge[i].to ; if( dis[v] < 0 && edge[i].vi > 0 ) { dis[v] = dis[u] + 1 ; Q.push( v ) ; } } } return dis[t] > 0 ; } int dfs( int u , int tmp ) { if( u == t ) return tmp ; int cost = 0 , an = 0 ; for( int i = cur[u] ; ~i ; i = edge[i].nxt ) { int v = edge[i].to ; if( dis[v] != dis[u] + 1 ) continue ; an = dfs( v , min( tmp - cost , edge[i].vi) ) ; edge[i].vi -= an ; edge[i^1].vi += an ; if( edge[i].vi ) cur[u] = i ; cost += an ; if( cost == tmp ) return cost ; } if( !cost ) dis[u] = -1 ; return cost ; } void sov( ) { while( bfs( ) ) { for( int x = 1 ; x <= n ; ++x ) cur[x] = head[x] ; cur[s] = head[s] , cur[t] = head[t] ; sum += dfs( s , inf ) ; } } bool cmp( A a , A b ) { if( a.a < b.a ) return 1 ; if( a.a == b.a && a.b < b.b ) return 1 ; return 0 ; } void output( ) { if( !sum ) { printf( "No Solution! " ) ; return ; } printf( "%d " , sum ) ; int tot = 0 ; for( int x = 2 ; x <= cnt ; ++x ) { // cout<<edge[x].fro<<" "<<edge[x].to<<" "<<edge[x].vi<<endl; if( !edge[x].vi && edge[x].fro != s && edge[x].to != t && edge[x].fro != t && edge[x].to != s && edge[x].fro < edge[x].to ) ans[++tot].a = edge[x].fro , ans[tot].b = edge[x].to ; } sort( ans + 1 , ans + 1 + tot , cmp ) ; for( int x = 1 ; x <= tot ; x++ ) printf( "%d %d " , ans[x].a , ans[x].b ) ; } int main( ) { // Init( ) ; input( ) ; sov( ) ; output( ) ; // fclose( stdin ) ; // fclose( stdout ) ; return 0 ; }
嗯 ,二分图匹配问题,可以用匈牙利算法乱搞 , 当然我是用网络流 ,建一个超级源点和汇点 ,反正就是这样 , codevs测评机有问题我也不知道过不过得了。