农夫为他的 N (1 ≤ N ≤ 100) 牛准备了 F (1 ≤ F ≤ 100)种食物和 D (1 ≤ D ≤ 100) 种饮料。每头牛都有各自喜欢的食物和饮料,而每种食物或饮料只能分配给一头牛。最多能有多少头牛可以同时得到喜欢的食物和饮料?
Input
第一行输入三个整数N, F, D
接下来n行,每行先输入两个整数 Fi 和 Di,分别表示编号为 i 的牛喜欢的食物和饮料的数量,接下来的Fi个整数表示第i头牛喜欢的食物的编号,最后Di个整数表示第i头牛喜欢的饮料的编号。
Output
输出同时得到喜欢的食物和饮料的牛的数量的最大值。
Sample Input
4 3 3
2 2 1 2 3 1
2 2 2 3 1 2
2 2 1 3 1 2
2 1 1 3 3
Sample Output
3
一开始建图我就建错了
源点 牛 食物 饮料 汇点
这样是不对的 因为这样让牛能喝的饮料数变多了
应该是
源点 食物 牛 牛 饮料 汇点
牛和牛是同一头牛 ,因为这样可以保证牛的通过量只能为1 这就是所谓的拆点吧
#include<iostream> #include<queue> #include<string.h> #include<stdio.h> #include<algorithm> using namespace std; const int maxn=500; const int inf=0x3f3f3f; int N; int depth[maxn]; int a[maxn][maxn]; bool bfs(int s,int e) { queue<int>q; memset(depth,-1,sizeof(depth)); depth[s]=0; q.push(s); while(!q.empty()) { int now=q.front(); q.pop(); for(int i=1;i<=N;i++) { if(depth[i]==-1&&a[now][i]) { depth[i]=depth[now]+1; q.push(i); } } } return depth[e]>0; } int dfs(int now,int e,int nowflow) { if(now==N) return nowflow; int findflow=0; for(int i=1;i<=N;i++) { if(a[now][i]&&depth[i]==depth[now]+1) { findflow=dfs(i,e,min(nowflow,a[now][i])); if(findflow) { a[now][i]-=findflow; a[i][now]+=findflow; return findflow; } } } if(!findflow) depth[now]=-2; return false; } int dinic(int s,int e) { int maxflow=0; while(bfs(s,e)) maxflow+=dfs(s,e,1<<20); return maxflow; } int main() { int n,f,d; while(scanf("%d%d%d",&n,&f,&d)!=EOF) { memset(a,0,sizeof(a)); N=f+d+2*n+2; for(int i=1;i<=f;i++) a[1][i+1]=1; for(int i=1;i<=n;i++) a[i+f+1][i+f+1+n]=1; for(int i=1;i<=d;i++) a[i+1+f+2*n][2+f+2*n+d]=1; for(int i=1;i<=n;i++) { int t1,t2,t3; cin>>t1>>t2; for(int j=1;j<=t1;j++) { cin>>t3; a[t3+1][i+1+f]=1; } for(int j=1;j<=t2;j++) { cin>>t3; a[i+1+f+n][t3+1+f+2*n]=1; } } cout<<dinic(1,N)<<endl; } }