题目:
http://poj.org/problem?id=3281
题意:
有N头牛,F种食物D种饮料,每头牛都有各自喜欢的食物和饮料,但是每一种只能分给一头牛,求出最多有几头牛可以得到喜欢的食物和饮料。
思路:
拆点网络流。
连接边为:s->食物->牛->牛->饮料->t, 容量都为1.
AC.
#include <iostream>
#include <cstdio>
#include <vector>
#include <cstring>
using namespace std;
const int INF = 1e9;
const int maxn = 405;
int N, F, D;
int food[maxn][maxn], drink[maxn][maxn];
struct edge { int to, cap, rev; };
vector<edge> g[maxn];
bool used[maxn];
void addedge(int from, int to, int cap)
{
g[from].push_back((edge) {to, cap, g[to].size()});
g[to].push_back((edge) {from, 0, g[from].size()-1});
}
int dfs(int v, int t, int f)
{
if(v == t) return f;
used[v] = true;
for(int i = 0; i < g[v].size(); ++i) {
edge &e = g[v][i];
if(!used[e.to] && e.cap > 0) {
int d = dfs(e.to, t, min(f, e.cap));
if(d > 0) {
e.cap -= d;
g[e.to][e.rev].cap += d;
return d;
}
}
}
return 0;
}
int max_flow(int s, int t)
{
int flow = 0;
while(1) {
memset(used, 0, sizeof(used));
int f = dfs(s, t, INF);
if(f == 0) return flow;
flow += f;
}
}
void solve()
{
int s = N * 2 + F + D, t = s + 1;
for(int i = 0; i < F; ++i) {
addedge(s, N*2+i, 1);
}
for(int i = 0; i < D; ++i) {
addedge(N*2+F+i, t, 1);
}
for(int i = 0; i < N; ++i) {
addedge(i, N+i, 1);
for(int j = 0; j < F; ++j) {
if(food[i][j]) addedge(N*2+j, i, 1);
}
for(int j = 0; j < D; ++j) {
if(drink[i][j]) addedge(N+i, N*2+F+j, 1);
}
}
printf("%d\n", max_flow(s, t));
}
int main()
{
//freopen("in", "r", stdin);
while(~scanf("%d %d %d", &N, &F, &D)) {
int f, d, t;
memset(food, 0, sizeof(food));
memset(drink, 0, sizeof(drink));
for(int i = 0; i < N; ++i) {
scanf("%d%d", &f, &d);
for(int j = 0; j < f; ++j) {
scanf("%d", &t);
t--;
food[i][t] = 1;
}
for(int j = 0; j < d; ++j) {
scanf("%d", &t);
t--;
drink[i][t] = 1;
}
}
solve();
}
return 0;
}