原题:http://poj.org/problem?id=3281
题意:有F种食物,D种饮料,N头牛;下面N行给出每头牛喜欢的食物种数和饮料种数,并且分别给出喜欢的食物的种类和饮料的种类;
问最多可以满足几头牛吃到自己喜欢的食物和饮料;
每种食物或者饮料只能提供给一头牛,每头牛只能吃一种食物和饮料;
思路:建立一个超级源点 s 和一个超级汇点 t ,因为食物和饮料之间没有直接关系,所以我们把牛放在食物和饮料之间,并且对牛进行拆点,因为一头牛只能吃一种食物、一种饮料,所以我们建立牛和牛之间容量为 1 的边来限制这个条件;另外 s 到食物建立容量 = 1 的边,饮料到 t 建立容量 = 1 的边,以此满足每种食物和饮料只能给一头牛提供;喜欢的食物和牛,牛和喜欢的饮料之间也均建立容量 = 1 的边;
#include<cstdio> #include<cstring> #include<string> #include<queue> #include<vector> #include<algorithm> #define inf 0x3f3f3f3f using namespace std; const int maxn = 50000; int n, f, d; int num_nodes; struct Edge { int from, to, flow, cap; }edge[maxn*2]; vector<int>G[maxn]; int edgenum; void add(int u, int v, int c) { edge[edgenum].from = u; edge[edgenum].to = v; edge[edgenum].flow = 0; edge[edgenum].cap = c; edgenum++; edge[edgenum].from = v; edge[edgenum].to = u; edge[edgenum].flow = 0; edge[edgenum].cap = 0; edgenum++; G[u].push_back(edgenum-2); G[v].push_back(edgenum-1); } int deep[maxn]; bool vis[maxn]; void BFS(int s, int t) { queue<int>Q; memset(vis, false, sizeof vis); Q.push(t); vis[t] = true; deep[t] = 0; while(!Q.empty()) { int now = Q.front(); Q.pop(); for(int i = 0;i<(int)G[now].size();i++) { int v = edge[G[now][i]].to; if(!vis[v]) { deep[v] = deep[now] + 1; vis[v] = true; Q.push(v); } } } } int gap[maxn], front[maxn], cur[maxn]; int Augment(int s, int t) { int minflow = inf; int begin = t; while(begin != s) { Edge& e = edge[front[begin]]; minflow = min(minflow, e.cap - e.flow); begin = e.from; } begin = t; while(begin != s) { edge[front[begin]].flow += minflow; edge[front[begin]^1].flow -= minflow; begin = edge[front[begin]].from; } return minflow; } int Maxflow(int s, int t) { int flow = 0; BFS(s, t); memset(gap, 0, sizeof gap); memset(cur, 0, sizeof cur); for(int i = 0;i<num_nodes;i++) gap[deep[i]]++; int begin = s; while(deep[s] < num_nodes) { if(begin == t) { flow += Augment(s, t); begin = s; } bool flag = false; for(int i = cur[begin];i<(int)G[begin].size();i++) { Edge& e = edge[G[begin][i]]; if(e.cap > e.flow && deep[begin] == deep[e.to] + 1) { front[e.to] = G[begin][i]; cur[begin] = i; flag = true; begin = e.to; break; } } if(!flag) { int k = num_nodes-1; for(int i = 0;i<(int)G[begin].size();i++) { Edge& e = edge[G[begin][i]]; if(e.cap > e.flow) k = min(k, deep[e.to]); } if(--gap[deep[begin]] == 0) break; gap[deep[begin] = k+1]++; cur[begin] = 0; if(begin != s) { begin = edge[front[begin]].from; } } } return flow; } void init() { for(int i = 0;i<n+2;i++) G[i].clear(); edgenum = 0; memset(deep, 0, sizeof deep); } int main() { while(~scanf("%d%d%d", &n, &f, &d)) { init(); for(int i = 1;i<=n;i++) { int fx, dx; scanf("%d%d", &fx, &dx); while(fx--) { int u; scanf("%d", &u); add(2*n+u, i, 1); } while(dx--) { int v; scanf("%d", &v); add(i+n, 2*n+f+v, 1); } } int s = 0, t = 2*n+f+d+1; for(int i = 1;i<=n;i++) add(i, n+i, 1); for(int i = 1;i<=f;i++) add(s, 2*n+i, 1); for(int i = 1;i<=d;i++) add(2*n+f+i, t, 1); num_nodes = t+1; int flow = Maxflow(s, t); printf("%d\n", flow); } return 0; }