POJ 3281 Dining
题目大意:
有N只牛,每只牛都偏爱吃一种食和饮料,现在有F种食物,D种饮料,现在想要给尽可能多的牛一份美餐。
输入数据:
一个N代表N只牛, F代表有F种食物, D代表有D种饮料。
接下来N行,
第i行代表,第i只牛,每行前两个数,Fi, Di 分别代表第i只牛喜欢的食物有Fi种,喜欢的饮料有Di种。
然后是Fi个数字,和Di个数字。
===========================================================================================
把牛拆开, 使得牛与牛之间的流量为 1, 虚拟一个源点 虚拟一个汇点。
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #include<cmath> #include<queue> using namespace std; typedef long long LL; const int INF = 1e9+7; const int maxn = 5005; const int MOD = 1e9+7; int n, F, D, k; int Layer[maxn], Head[maxn]; struct Edge { int from, to, flow; int next; } edge[maxn*2]; void AddEdge(int from,int to,int flow) { edge[k].from = from; edge[k].to = to; edge[k].flow = flow; edge[k].next = Head[from]; Head[from] = k ++; swap(from, to); edge[k].from = from; edge[k].to = to; edge[k].flow = 0; edge[k].next = Head[from]; Head[from] = k ++; } bool BfsLayer(int Star,int End) { queue<int> Q; memset(Layer, -1, sizeof(Layer)); Layer[Star] = 1; Q.push(Star); while( Q.size() ) { int s = Q.front(), to; Q.pop(); if(s == End) return true; for(int i=Head[s]; i != -1; i=edge[i].next) { to = edge[i].to; if( Layer[to] == -1 && edge[i].flow) { Q.push(to); Layer[to] = Layer[s] + 1; } } } return false; } int DFS(int Star,int End,int MaxFlow) { if(Star == End)///如果已经到达汇点 return MaxFlow; int sFlow = 0;///这点到达汇点的流量 for(int i=Head[Star]; i != -1; i=edge[i].next) { int to = edge[i].to; int flow = edge[i].flow; if(Layer[Star] + 1 == Layer[to] && flow) { flow = min(MaxFlow-sFlow, flow);/// (到达Star的最大流量 - 从Star流出的流量,路径上最大限制的流量) = 到达下一个点的最大流量 flow = DFS(to, End, flow);///返回to可以到达汇点的最大流量 sFlow += flow; edge[i].flow -= flow; edge[i^1].flow += flow; if(sFlow == MaxFlow)///改点已经不能再分配出其他流量了。 break; } } if(sFlow == 0)///这个点已经不能再向汇点输送流量了。 Layer[Star] = -1; return sFlow; } int Dinic(int Star,int End) { int ans = 0; while( BfsLayer(Star, End) ) { ans += DFS(Star, End, INF); } return ans; } int main() { while(cin >> n >> F >> D) { int Fi, Di, f, d; int N1=F, N2=N1+n, Ds=N2+n, start=Ds+D+1, End=start+1; k = 0; memset(Head, -1, sizeof(Head)); for(int i=1; i<=n; i++) { cin >> Fi >> Di; AddEdge(N1+i, N2+i, 1);///把牛拆点建图,建立牛一和牛二之间的联系 for(int j=0; j<Fi; j++) { cin >> f; AddEdge(f, N1+i, 1);///建立食物和牛一之间的联系 } for(int j=0; j<Di; j++) { cin >> d; AddEdge(N2+i, Ds+d, 1);///建立牛二和饮料之间的联系 } } for(int i=1; i<=F; i++) AddEdge(start, i, 1); for(int i=1; i<=D; i++) AddEdge(Ds+i, End, 1); printf("%d\n", Dinic(start, End) ); } return 0; }