Description
FJ的奶牛们只吃各自喜欢的一些特定的食物和饮料,除此之外的其他食物和饮料一概不吃。某天FJ为奶牛们精心准备了一顿美妙的饭食,但在之前忘记检查奶牛们的菜单,这样显然是不能不能满足所有奶牛的要求。但是FJ又不愿意为此重新来做,所以他他还是想让尽可能多的牛吃到他们喜欢的食品和饮料。
FJ提供了F (编号为1、2、…、F)种食品并准备了D (编号为1、2、…、D)种饮料, 他的N头牛(编号为1、2、…、N)都已决定了是否愿意吃某种食物和喝某种饮料。FJ想给每一头牛一种食品和一种饮料,使得尽可能多的牛得到喜欢的食物和饮料。
每一种食物和饮料只能由一头牛来用。例如如果食物2被一头牛吃掉了,没有别的牛能吃到食物2。
【输入】第一行包含三个用空格分开的整数N,F和D;接下来的N行描述每个奶牛的信息:第i+1行的前两个整数为F_i和D_i,接下来的F_i个整数表示奶牛i喜欢的食品编号,再接下来的D_i个整数表示奶牛i喜欢的饮料编号。
【输出】仅一行一个整数,表示FJ最多能让多少头奶牛吃到自己喜欢的食品和饮料。
【样例】
Dining.in |
Dining.out |
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 |
3
|
【样例说明】
输入数据表明:奶牛1喜欢的食物1、2;喜欢喝饮料3、1;奶牛2喜欢的食物2、3;喜欢喝饮料1、2;奶牛3喜欢的食物1、3;喜欢喝饮料1、2;奶牛4喜欢的食物1、3;喜欢喝饮料3;
那么下面的分配方法将是最优的:奶牛1不给食品和饮料;奶牛2分配食物2和饮料2;奶牛3分配食物1和饮料2;奶牛4分配食物3和饮料3。
【数据范围】
1<=F<=100,1<=D<=100,1<=N<=100
建图有点麻烦,其它照常。
#include <iostream>
#include <queue>
#include <cstring>
#define SIZE 5010
#define INF 1e+09
using namespace std;
struct edge
{
int to, cap, reverse;
};
vector<edge> graph[SIZE];
int depth[SIZE], sink;
bool bfs(int start)
{
int i, u, v;
queue<int> q;
memset(depth, -1, sizeof (depth));
depth[start] = 0;
q.push(start);
while (!q.empty())
{
u = q.front();
q.pop();
if (u == sink)
{
return true;
}
for (i = 0; i < graph[u].size(); ++i)
{
v = graph[u][i].to;
if ((depth[v] == -1) && (graph[u][i].cap > 0))
{
depth[v] = depth[u] + 1;
q.push(v);
}
}
}
return false;
}
int dfs(int u, int flow)
{
int i, v, ret = 0, delta;
if (u == sink)
{
return flow;
}
for (i = 0; i < graph[u].size(); ++i)
{
edge &temp = graph[u][i];
v = temp.to;
if ((temp.cap > 0) && (depth[v] == depth[u] + 1))
{
delta = dfs(v, min(flow - ret, temp.cap));
if (delta > 0)
{
ret += delta;
temp.cap -= delta;
graph[v][temp.reverse].cap += delta;
}
if (ret == flow)
{
return ret;
}
}
}
return ret;
}
int dinic(int start) // Dinic算法模板
{
int maxflow = 0, delta;
while (bfs(start))
{
delta = dfs(start, INF);
if (!delta)
{
break;
}
maxflow += delta;
}
return maxflow;
}
void addedge(int u, int v, int cap)
{
graph[u].push_back({v, cap, graph[v].size()});
graph[v].push_back({u, 0, graph[u].size() - 1});
return;
}
int main(int argc, char** argv)
{
int n, f, d, count, count2, x, i;
scanf("%d%d%d", &n, &f, &d);
for (i = 1; i <= n; ++i) // 见图
{
addedge(f + i, f + n + i, 1); // 容量限制
scanf("%d%d", &count, &count2);
while (count--)
{
scanf("%d", &x);
addedge(x, f + i, 1); // 食物→奶牛
}
while (count2--)
{
scanf("%d", &x);
addedge(f + n + i, f + n + n + x, 1); // 奶牛→饮料
}
}
sink = f + n + n + d + 1;
for (i = 1; i <= f; ++i)
{
addedge(0, i, 1); // 源点→食物
}
for (i = 1; i <= d; ++i)
{
addedge(f + n + n + i, sink, 1); // 饮料→汇点
}
printf("%d", dinic(0));
return 0;
}