http://poj.org/problem?id=3281
题意:
农夫有n头牛,F种食物,D种饮料,每头牛都有各自喜欢的食物和饮料,问最多有几头牛吃到自己喜欢的东西
思路:
可以用最大流写,
一个超级源点S连接食物,一个超级汇点T连接饮料,食物与对应的牛连接,牛与对应的饮料连接。
但是得把牛的点拆开,因为牛只有一个,牛自身的流量为1,如果不把牛给拆开的话,会把最大流量算大
比如这样:
这样的话,最大流跑出来的是2,而牛只有一只,所以答案应该是1
因此把牛与牛之间建一条容量为1的边即可
像这样
#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <math.h>
#include <vector>
#include <set>
#include <map>
#include <string>
#include <string.h>
#include <queue>
#include <stack>
#include <deque>
#include <stdlib.h>
#include <bitset>
using namespace std;
#define ll long long
#define ull unsigned long long
#define INF 0x3f3f3f3f
#define maxn 105
#define eps 0.00000001
#define PI acos(-1.0)
#define M 1e9 + 7
int N, F, D;
int mp[4 * maxn][4 * maxn], dis[4 * maxn];
int st = 1, en;
int bfs() {
memset(dis, -1, sizeof(dis));
dis[en] = 0;
queue<int> que;
que.push(en);
while(!que.empty()) {
int u = que.front(); que.pop();
for (int i = st; i <= en; i ++) {
if(dis[i] == -1 && mp[i][u]) {
dis[i] = dis[u] + 1;
que.push(i);
}
}
}
return dis[st] != -1;
}
int dfs(int u, int flow) {
int a = 0;
if(u == en) return flow;
for (int i = st; i <= en; i ++) {
if(dis[u] == dis[i] + 1 && mp[u][i] && (a = dfs(i, min(flow, mp[u][i])))) {
mp[u][i] -= a;
mp[i][u] += a;
return a;
}
}
return 0;
}
int dinic() {
int ans = 0;
while(bfs())
ans += dfs(1, INF);
return ans ;
}
int main(int argc, const char * argv[]) {
memset(mp, 0, sizeof(mp));
scanf("%d %d %d", &N, &F, &D);
en = 2 + 2 * N + F + D;
for (int i = st + 1; i <= F + st; i ++) //源点到食物
mp[st][i] = 1;
for (int i = st + F + 2 * N + 1; i <= 1 + F + 2 * N + D; i ++) //饮料到汇点
mp[i][en] = 1;
for (int i = 1; i <= N; i ++) {
mp[st + F + i][st + F + N + i] = 1;
int f, d;
scanf("%d %d", &f, &d);
for (int j = 1, x; j <= f; j ++) {
scanf("%d", &x);
mp[st + x][i + F + st] = 1; //食物到牛
}
for (int j = 1, x; j <= d; j ++) {
scanf("%d", &x);
mp[i + F + N + st][st + x + F + 2 * N] = 1;//牛到饮料
}
}
printf("%d\n", dinic());
return 0;
}