题意:有F种食物和D种饮料,每种食物或饮料只能供一头牛享用,且每头牛只享用一种食物和一种饮料。现在有n头牛,每头牛都有自己喜欢的食物种类列表和饮料种类列表,问最多能使几头牛同时享用到自己喜欢的食物和饮料。(1 <= f <= 100, 1 <= d <= 100, 1 <= n <= 100)
思路:EK算法,拆点。
参考博客:http://blog.sina.com.cn/s/blog_6635898a0100ly5j.html
http://blog.csdn.net/zhang20072844/article/details/8122626
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <math.h> #define inf 1000 #define nMax 410 #define Max(a,b) (a>b?a:b) #define Min(a,b) (a<b?a:b) int map[nMax][nMax]; int N,F,D; int path[nMax]; int queue[nMax * 100]; int head,end; //bool flag[nMax]; //广搜求一条增广路 int bfs() { int minFlow = inf,u; memset(path, -1, sizeof(path)); head = 0; end = 1; queue[head] = 0; while (head < end) { u = queue[head ++]; if (u == 2 * N + F + D + 1) { break; } for (int i = 1; i <= 2 * N + F + D + 1; ++ i) { if (path[i] == -1 && map[u][i] ) { if (minFlow > map[u][i]) { minFlow = map[u][i]; } queue[end ++] = i; path[i] = u; } } } if (path[2 * N + F + D + 1] == -1) { return -1; } return minFlow; } //EK算法,每次广搜得到一条增广路径,然后更新残留网络 void Edmods_Karp() { int flow, maxFlow = 0, now, pre; while ((flow = bfs()) != -1) { maxFlow += flow; now = 2 * N + F + D + 1; while (now != 0) { pre = path[now]; map[pre][now] -= flow; map[now][pre] += flow; now = pre; } } printf("%d\n", maxFlow); } //按照源点-食物-牛-牛-饮料-汇点的顺序建图 void buildMap() { int fNum,dNum,fd; while (scanf("%d %d %d", &N, &F, &D) != EOF) { memset(map, 0, sizeof(map)); //memset(flag, false, sizeof(flag)); for (int i = 1; i <= N; ++ i) { scanf("%d %d", &fNum, &dNum); for (int j = 0; j < fNum; ++ j) { scanf("%d", &fd); map[0][fd] = 1; map[fd][i + F] = 1; } map[i + F][i + F + N] = 1; for (int j = 0; j < dNum; ++ j) { scanf("%d", &fd); map[fd + 2 * N + F][F + 2 * N + D + 1] = 1; map[i + F + N][fd + 2 * N + F] = 1; } } Edmods_Karp(); } } //注意这里给点编号,0-源点,1-F是食物,F+1-F+N是牛左点,F+N+1-F+N+N是牛右点,F+N+N+1-F+N+N+D是drink饮料点,F+N+N+D+1是汇点 int main() { buildMap(); return 0; }