Source:POJ-3281
Description
Cows are such finicky eaters. Each cow has a preference for certain foods and drinks, and she will consume no others.Farmer John has cooked fabulous meals for his cows, but he forgot to check his menu against their preferences. Although he might not be able to stuff everybody, he wants to give a complete meal of both food and drink to as many cows as possible.Farmer John has cooked F (1 ≤ F ≤ 100) types of foods and prepared D (1 ≤ D ≤ 100) types of drinks. Each of his N (1 ≤ N ≤ 100) cows has decided whether she is willing to eat a particular food or drink a particular drink. Farmer John must assign a food type and a drink type to each cow to maximize the number of cows who get both.Each dish or drink can only be consumed by one cow (i.e., once food type 2 is assigned to a cow, no other cow can be assigned food type 2).
Input
Line 1: Three space-separated integers: N, F, and D
Lines 2..N+1: Each line i starts with a two integers Fi and Di, the number of dishes that cow i likes and the number of drinks that cow i likes. The next Fi integers denote the dishes that cow i will eat, and the Di integers following that denote the drinks that cow i will drink.
Output
Line 1: A single integer that is the maximum number of cows that can be fed both food and drink that conform to their wishes
Sample Input
4 3 3
2 2 1 2 3 1
2 2 2 3 1 2
2 2 1 3 1 2
2 1 1 3 3
Sample Output
3
Hint
One way to satisfy three cows is:
Cow 1: no meal
Cow 2: Food #2, Drink #2
Cow 3: Food #1, Drink #1
Cow 4: Food #3, Drink #3
源代碼:
#include<iostream>
#include<cstring>
#include<queue>
using namespace std;
queue <int> Q;
const int MAX = 600;
const int INF = 1<<30;
int C , F , D , Fi , Di , S , T;
int mark[MAX] , level[MAX];
int map[MAX][MAX];
//C是牛的數目,F是食物的數目,D是飲料的數目,S是源點,T是匯點
//圖爲源點->食物->左牛->右牛->飲料->匯點
//兩個牛集合保證了每頭牛隻能選擇一批(一個食物和一瓶飲料)物品
int Dinic( void );
int bfs( void );
int dfs( int u , int flow );
int min( int a , int b ){ return a <= b ? a : b; }
int main( ){
int i , j , k , ff , dd;
while( cin>>C>>F>>D ){
S = 0 ; //源點爲0
T = F + C + C + D + 1; //匯點爲總點數+1
memset( map , 0 , sizeof( map ) ); //地圖初始化
for( i=1 ; i<=F ; i++ )
map[S][i] = 1; //源點->食物
for( k=1 ; k<=C ; k++ ){
cin>>Fi>>Di;
for( j=1 ; j<=Fi ; j++ ){ //食物->左牛集合
cin>>ff;
map[ff][k+F] = 1;
}
map[k+F][k+F+C] = 1; //左牛集合->右牛集合
for( j=1 ; j<=Di ; j++ ){
cin>>dd;
map[k+F+C][dd+F+C+C] = 1; //右牛集合->飲料
}
}
for( i=1 ; i<=D ; i++ )
map[i+F+2*C][T] = 1; //飲料->匯點
cout<<Dinic( );
}
return 0;
}
int Dinic( void ){
int sum=0;
while( bfs( ) ){
sum += dfs( S , INF );
}
return sum;
}
int bfs( void ){
int u , v;
memset( mark , 0 , sizeof( mark ) );
memset( level , 0 , sizeof( level ) );
while( !Q.empty() )
Q.pop( );
Q.push( S );
mark[S] = 1;
while( !Q.empty() ){
u = Q.front( );
Q.pop( );
if( u==T )
return 1;
for( v=S ; v<=T ; v++ ){
if( !mark[v] && map[u][v] ){
Q.push( v );
mark[v] = 1;
level[v] = level[u] + 1; //層數加一
}
}
}
return 0;
}
int dfs( int u , int flow ){
int v , flowSum , sum=0;
if( u==T )
return flow;
for( v=S ; v<=T ; v++ ){
if( level[v]==level[u]+1 && map[u][v] ){
flowSum = dfs( v , min( flow , map[u][v] ) );
map[u][v] -= flowSum;
map[v][u] += flowSum;
flow -= flowSum; //流量值減少
sum += flowSum;
}
}
return sum;
}
代碼分析:我是參考了別人的思路寫出來的,個人覺得很精妙,牛化爲兩個子集,保證了只有一次選擇的機會.很巧的.