POJ3281 Dining(拆点构图 + 最大流)
题意:有F种食物,D种饮料N头奶牛,只能吃某种食物和饮料(而且只能吃特定的一份)
一种食物被一头牛吃了之后,其余牛就不能吃了
第一行有N,F,D三个整数
接着2-N+1行代表第i头牛,前面两个整数是Fi与Di(食物与饮料的种类数量),接着是食物的种类与饮料的种类
要求输出最多分配能够满足的牛的数量
分析:本想最大匹配搞,然后发现牛不仅要匹配食物还要匹配饮料。
最大流拆点构图, 食物 - 牛- 饮料,但是由于一个牛只能选择一个食物和一个饮料,也就是说牛这个节点有限制,最大就是1,然后把 牛这个节点拆成 牛 - 牛 其中之间流量是1,
于是 最后模型就是 食物 - 牛 - 牛 - 饮料 节点之间的流量都是1.
1 #include <iostream> 2 #include <cstdio> 3 #include <algorithm> 4 #include <queue> 5 #include <cstring> 6 using namespace std; 7 const int Max = 500; 8 const int INF = 0x3f3f3f3f; 9 int g[Max][Max]; 10 int N, F, D; 11 int pre[Max]; 12 int BFS() 13 { 14 memset(pre, -1, sizeof(pre)); 15 int MinFlow = INF; 16 queue<int> que; 17 pre[0] = 0; 18 que.push(0); 19 int des = F + 2 * N + D + 1; 20 while (!que.empty()) 21 { 22 int x = que.front(); 23 que.pop(); 24 if (x == des) 25 break; 26 for (int i = 1; i <= des; i++) 27 { 28 if (pre[i] == -1 && g[x][i]) 29 { 30 if (MinFlow > g[x][i]) 31 { 32 MinFlow = g[x][i]; 33 } 34 pre[i] = x; 35 que.push(i); 36 } 37 } 38 } 39 if (pre[des] == -1) 40 return -1; 41 return MinFlow; 42 } 43 void EK() 44 { 45 int MaxFlow = 0, inFlow = 0, des; 46 while ( (inFlow = BFS()) != -1) 47 { 48 MaxFlow += inFlow; 49 des = F + 2 * N + D + 1; 50 while (des != 0) 51 { 52 g[des][pre[des]] += inFlow; 53 g[pre[des]][des] -= inFlow; 54 des = pre[des]; 55 } 56 } 57 printf("%d\n", MaxFlow); 58 } 59 void buildGraph() 60 { 61 while (scanf("%d%d%d", &N, &F, &D) != EOF) 62 { 63 memset(g, 0, sizeof(g)); 64 int fd, fnum, dnum; 65 for (int i = 1; i <= N; i++) 66 { 67 scanf("%d%d", &fnum, &dnum); 68 for (int j = 0; j < fnum; j++) 69 { 70 scanf("%d", &fd); 71 g[0][fd] = 1; // 0点作为起点连接每个食物 72 g[fd][F + i] = 1; // 食物和牛相连,食物最大F, 73 } 74 g[F + i][F + N + i] = 1; // 牛 和 牛相连 75 for (int j = 1; j <= dnum; j++) 76 { 77 scanf("%d", &fd); 78 g[F + N + i][F + N + N + fd] = 1; // 牛和饮料相连 79 g[F + N + N + fd][F + N + N + D + 1] = 1; // 设一个终点让每一个 饮料 和他相连,流量为1 80 } 81 } 82 EK(); 83 } 84 } 85 int main() 86 { 87 buildGraph(); 88 return 0; 89 }