Problem Dscription
输入 n, f, d分别代表有n头牛,f种食物,d种饮料。接下来n行,每行输入F D f[1]..f[F] d[1]..d[D]。代表牛1有F种喜欢的食物,D种喜欢的饮料,分别是f[1]..f[F], d[1]..d[D]。每种食物只能给一个牛吃,每种饮料也只能给一个牛喝,意思就是给了牛A,就不能给牛B了。问你最多有多少头牛。能吃到食物同时喝到饮料?
思路:
核心是建图参考了挑战P235页。设置一个超级汇点0,和超级源点2*n+f+d+1。牛分为1 到 n,n+1 到 n+n两个点。食物2*n+1 到 2*n+f。 饮料2*n+f+1 到 2*n+f+d。
超级源点到所有食物连边流量为1。所有的饮料到超级汇点连边流量为1。食物到牛第一个点连边,按照题目所给,流量为1。牛得拆分成两个点目的是为了限制到牛的流量只能是1,所以拆成两个点连边流量为1。牛第二个点到饮料连边,按照题目所给,流量为1。然后求最大流就好了。
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
struct node
{
int to, w, next;
};
node Map[50000];
int head[500], vis[500], cnt;
int dfs(int s, int t, int f)
{
vis[s] = 1;
if(s == t) return f;
for(int i = head[s]; ~i; i = Map[i].next)
{
int to = Map[i].to, &w = Map[i].w;
if(!vis[to] && w)
{
int d = dfs(to, t, min(f, w));
if(d > 0)
{
w -= d;
Map[i^1].w += d;
return d;
}
}
}
return 0;
}
int ek(int s, int t)
{
int Max_flow = 0;
for(;;)
{
memset(vis, 0, sizeof(vis));
int d = dfs(s, t, 0x3f3f3f3f);
if(d == 0) break;
Max_flow += d;
}
return Max_flow;
}
void add(int u, int v, int w)//前向星
{
Map[cnt].to = v;
Map[cnt].w = w;
Map[cnt].next = head[u];
head[u] = cnt++;
Map[cnt].to = u;
Map[cnt].w = 0;
Map[cnt].next = head[v];
head[v] = cnt++;
}
int main()
{
int n, f, d, F, D, food, drink;
while(~scanf("%d %d %d", &n, &f, &d))
{
cnt = 0;
memset(head, -1, sizeof(head));
for(int i = 1; i <= f; i++)//超级源点到食物
add(0, 2*n+i, 1);
for(int i = 1; i <= d; i++)//饮料到超级汇点
add(2*n+f+i, 2*n+f+d+1, 1);
for(int i = 1; i <= n; i++)
{
add(i, i+n, 1);//牛到牛之间
scanf("%d %d", &F, &D);
while(F--)
{
scanf("%d", &food);
add(2*n+food, i, 1);//食物到牛第一个点
}
while(D--)
{
scanf("%d", &drink);
add(i+n, 2*n+f+drink, 1);//牛第二个点到饮料
}
}
printf("%d\n", ek(0, 2*n+f+d+1));//输出最大流
}
return 0;
}