洛谷传送门
BZOJ传送门
题目描述
有 F F 种食物和种饮料,每种食物或饮料只能供一头牛享用,且每头牛只享用一种食物和一种饮料。现在有 n n 头牛,每头牛都有自己喜欢的食物种类列表和饮料种类列表,问最多能使几头牛同时享用到自己喜欢的食物和饮料。()
输入输出格式
输入格式
第一行三个整数 N,F,D N , F , D 。
第二行至第 N+1 N + 1 行, 每行若干整数。前两个整数 Fi,Di F i , D i 表示标号为 i i 的牛喜欢的食物、饮料种类。 后面个整数表示其喜欢食物的标号, 接下来 Di D i 个整数表示其喜欢的饮料的标号。
输出格式
一行一个整数 x x , 表示最多有头牛同时获得自己喜欢的食物和饮料。
输入输出样例
输入样例#1
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
输出样例#1
3
解题分析
如果把牛放在一边, 食物、饮料放在另一边, 连边就变得困难起来, 无法保证一头牛同时获得喜欢的食物和饮料。
换个思路, 我们把食物放在左边, 牛放在中间, 饮料放在右边, 之间连容量为 1 1 <script type="math/tex" id="MathJax-Element-13">1</script>的边, 跑一边最大流即可。
代码如下:
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cctype>
#include <cstdlib>
#include <cmath>
#include <queue>
#define R register
#define IN inline
#define gc getchar()
#define W while
#define MX 40050
#define S 0
#define T 1000
#define base 100
#define INF 100000000
template <class TT>
IN void in(TT &x)
{
x = 0; R char c = gc;
W (!isdigit(c)) c = gc;
W (isdigit(c))
x = (x << 1) + (x << 3) + c - 48, c = gc;
}
int num, f, d, cnt = -1;
int head[1005], layer[1005];
std::queue <int> q;
struct Edge {int to, fl, nex;} edge[MX << 1];
IN void add(R int from, R int to, R int fl)
{edge[++cnt] = {to, fl, head[from]}, head[from] = cnt;}
IN bool BFS()
{
std::memset(layer, 0, sizeof(layer));
layer[S] = 1; q.push(S);
R int now;
W (!q.empty())
{
now = q.front(); q.pop();
for (R int i = head[now]; ~i; i = edge[i].nex)
{
if(edge[i].fl && !layer[edge[i].to])
layer[edge[i].to] = layer[now] + 1, q.push(edge[i].to);
}
}
return layer[T];
}
int DFS(R int now, R int val)
{
if(now == T) return val;
int lef = val, buf;
for (R int i = head[now]; ~i; i = edge[i].nex)
{
if(edge[i].fl && layer[edge[i].to] == layer[now] + 1)
{
buf = DFS(edge[i].to, std::min(lef, edge[i].fl));
if(!buf) continue;
lef -= buf; edge[i].fl -= buf, edge[i ^ 1].fl += buf;
if(lef <= 0) return val;
}
}
return val - lef;
}
int Dinic()
{
int ret = 0;
W (BFS()) ret += DFS(S, INF);
return ret;
}
int main(void)
{
int a, b, c;
in(num), in(f), in(d);
std::memset(head, -1, sizeof(head));
for (R int i = 1; i <= f; ++i) add(S, i, 1), add(i, S, 0);
for (R int i = 1; i <= num; ++i) add(i + base, i + base * 2, 1), add(i + base * 2, i + base, 0);
for (R int i = 1; i <= d; ++i) add(i + base * 3, T, 1), add(T, i + base * 3, 0);
for (R int i = 1; i <= num; ++i)
{
in(a), in(b);
for (R int j = 1; j <= a; ++j)
in(c), add(c, i + base, 1), add(i + base, c, 0);
for (R int j = 1; j <= b; ++j)
in(c), add(i + base * 2, c + base * 3, 1), add(c + base * 3, i + base * 2, 0);
}
printf("%d", Dinic());
}