题意:
农夫约翰为他的牛准备了F种食物和D种饮料。每头牛都有各自喜欢的食物和饮料,而每种食物或饮料只能分配给一头牛。最多能有多少头牛可以同时得到各自喜欢的食物和饮料?
思路:
用 s -> 食物 -> 牛 -> 牛 -> 饮料 -> t 为路径,建图。然后跑最大流。
p.ps.: 抄的书上的思路和dfs增广路的模板,当做学习网络流的第一步吧 :)
代码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #include <vector> 5 using namespace std; 6 7 const int MAXV = 500; 8 const int INF = 0x7fffffff; 9 10 struct edge { 11 int to; //边的终点 12 int cap; //容量 13 int rev; //反向边的编号 14 }; 15 16 vector<edge> G[MAXV]; //图的邻接表表示 17 bool used[MAXV]; //DFS中用到的访问标记 18 19 //向图中增加一条从s到t容量为cap的边 20 void addEdge(int from, int to, int cap) { 21 G[from].push_back((edge){to, cap, G[to].size()}); 22 G[to].push_back((edge){from, 0, G[from].size()-1}); 23 } 24 25 //dfs找增广路 26 int dfs(int v, int t, int f) { 27 if (v==t) return f; 28 29 used[v] = true; 30 for (int i = 0; i < G[v].size(); i++) { 31 edge &e = G[v][i]; 32 if (!used[e.to] && e.cap>0) { 33 int d = dfs(e.to, t, min(f, e.cap)); 34 if (d>0) { //如果找到一条可行路 35 e.cap -= d; //容量减少 36 G[e.to][e.rev].cap += d; //反向边容量增加 37 return d; //找到一条可行路就返回 38 } 39 } 40 } 41 return 0; 42 } 43 44 //求解从s到t的最大流 45 int maxFlow(int s, int t) { 46 int flow = 0; 47 int f = -1; 48 while (f!=0) { 49 memset(used, false, sizeof(used)); 50 f = dfs(s, t, INF); 51 flow += f; 52 } 53 return flow; 54 } 55 56 const int MAXN = 105; 57 58 int N, F, D; 59 bool likeF[MAXN][MAXN]; 60 bool likeD[MAXN][MAXN]; 61 62 void input() { 63 memset(likeF, false, sizeof(likeF)); 64 memset(likeD, false, sizeof(likeD)); 65 scanf("%d%d%d", &N, &F, &D); 66 for (int i = 0; i < N; i++) { 67 int f, d, t; 68 scanf("%d%d", &f, &d); 69 for (int j = 0; j < f; j++) { 70 scanf("%d", &t); 71 likeF[i][t-1] = true; 72 } 73 for (int j = 0; j < d; j++) { 74 scanf("%d", &t); 75 likeD[i][t-1] = true; 76 } 77 } 78 } 79 80 void solve() { 81 //0~N-1: 食物一侧的牛 82 //N~2N-1: 饮料一侧的牛 83 //2N~2N+F-1: 食物 84 //2N+F~2N+F+D: 饮料 85 int s = N*2+F+D, t = s+1; 86 87 //在s与食物之间连边 88 for (int i = 0; i < F; i++) { 89 addEdge(s, N*2+i, 1); 90 } 91 92 //在饮料和t之间连边 93 for (int i = 0; i < D; i++) { 94 addEdge(N*2+F+i, t, 1); 95 } 96 97 for (int i = 0; i < N; i++) { 98 //在两头牛之间连边 99 addEdge(i, N+i, 1); 100 101 //食物到牛 102 for (int j = 0; j < F; j++) if (likeF[i][j]) { 103 addEdge(N*2+j, i, 1); 104 } 105 //牛到饮料 106 for (int j = 0; j < D; j++) if (likeD[i][j]) { 107 addEdge(N+i, N*2+F+j, 1); 108 } 109 } 110 printf("%d ", maxFlow(s, t)); 111 } 112 113 int main() { 114 #ifdef Phantom01 115 freopen("PKU3281.txt", "r", stdin); 116 #endif // Phantom01 117 118 input(); 119 solve(); 120 121 return 0; 122 }