NYOJ题目连接:http://acm.nyist.edu.cn/JudgeOnline/problem.php?pid=326
POJ题目连接:http://poj.org/problem?id=3281
把牛的编号拆开,建边权值为1,避免一头牛选双份食物和饮料,建立一个超级源点并与所有食物编号建边,建立一个超级汇点并与所有饮料编号建边,求最大流即可。
参考代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define NN 405
#define MM 40500
#define CLR(arr,v) memset(arr,v,sizeof(arr))
int map[NN][NN],pre[NN],gap[NN],cnt[NN],stck[NN],top;
int que[NN],head,total;
bool vis[NN],flag;
int h[NN],num[MM],nex[MM],pos;
int FF[NN],DD[NN];
void init()
{
CLR(map,0); CLR(gap,0); CLR(cnt,0);
CLR(stck,0);CLR(que,0); CLR(nex,0);
CLR(vis,0); CLR(num,0); CLR(h,0);
pos = top = 0; flag = false;
}
void add(int u,int v)
{
num[++pos] = v;
nex[pos] = h[u];
h[u] = pos;
}
void init_gap(int n)
{
head = total = 0;
que[total++] = n;
vis[n] = true;
cnt[0] = 1;
while(head < total)
{
int p = que[head++];
if(head >= NN) head -= NN;
for(int i = h[p]; i ;i = nex[i])
{
if(!vis[ num[i] ])
{
vis[ num[i] ] = true;
gap[ num[i] ] = gap[ p] + 1;
cnt[ gap[num[i]] ]++;
que[total++] = num[i];
if(total >= NN) total -= NN;
}
}
}
}
bool dfs(int p,int t)
{
for(int i = h[p]; i ;i = nex[i])
{
if(gap[p] - gap[ num[i] ] == 1 && map[p][ num[i] ] > 0)
{
pre[ num[i] ] = p;
if(num[i] != t) stck[++top] = num[i];
if(num[i] == t || dfs(num[i],t)) return true;
}
}
cnt[ gap[p] ]--;
cnt[ gap[p]+1 ]++;
top--;
if(cnt[ gap[p] ] == 0) flag = true;
gap[p] += 1;
return false;
}
int MaxFlow(int s,int t)
{
init_gap(t);
int res = 0;
stck[top] = s;
while(!flag)
{
CLR(pre,-1);
if(top < 0) top = 0;
if(!dfs(stck[top],t)) continue;
int p = t;
res += 1;
while(pre[p] != -1)
{
map[ pre[p] ][p] -= 1;
map[p][ pre[p] ] += 1;
p = pre[p];
}
top = 0;
}
return res;
}
int main()
{
int F,N,D;
while(~scanf("%d%d%d",&N,&F,&D))
{
init();
int s = 0,f,d;
for(int i = 1;i <= N;++i)
{
map[i][i+N+F+D] = 1;
scanf("%d%d",&f,&d);
for(int j = 0;j < f;++j)
scanf("%d",&FF[j]);
for(int k = 0;k < d;++k)
scanf("%d",&DD[k]);
if(f == 0 || d == 0) continue;
for(int j = 0;j < f;++j)
map[ FF[j]+N ][i] = 1;
for(int j = 0;j < d;++j)
map[i+N+F+D][ DD[j]+N+F ] = 1;
}
int n = F + N * 2 + D + 1;
for(int i = F + N + 1,j = 1;j <= D;++j,++i)
map[i][n] = 1;
for(int i = N + 1,j = 1;j <= F;++j,++i)
map[0][i] = 1;
for(int i = 0;i <= n;++i)
{
for(int j = 0;j <= n;++j)
if(map[i][j])
{
add(i,j);
add(j,i);
}
}
printf("%d\n",MaxFlow(s,n));
}
return 0;
}