您的位置:首页 > 理论基础 > 计算机网络

poj 3181 网络流,建图。

2015-07-27 19:57 375 查看
题意:

农夫约翰为他的牛准备了F种食物和D种饮料。

每头牛都有各自喜欢的食物和饮料,而每种食物和饮料都只能分配给一头牛。

问最多能有多少头牛可以同时得到喜欢的食物和饮料。

解析:

由于要同时得到喜欢的食物和饮料,所以网络流建图的时候要把牛拆点了。

如下建图:

s -> 食物 -> 牛1 -> 牛2 -> 饮料 -> t

所以分配一下点:

s = 0,

牛1= 1~n,

牛2= n+1 ~ 2*n,

食物= 2*n+1 ~ 2 * n + f,

饮料= 2*n+f+1 ~ 2*n+f+d,

t = 2*n+f + d + 1。

然后按照流量方向建立一张有向图,接着求一个最大流就行了。

好方便。。。

代码:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <stack>
#include <vector>
#include <queue>
#include <map>
#include <climits>
#include <cassert>
#define LL long long
#define lson lo, mi, rt << 1
#define rson mi + 1, hi, rt << 1 | 1

using namespace std;
const int maxn = 400 + 10;//100牛*2 + 100食 + 100饮 + s + t
const int inf = 0x3f3f3f3f;
const double eps = 1e-8;
const double pi = acos(-1.0);
const double ee = exp(1.0);

int n, f, d;
int flow[maxn][maxn];
int cap[maxn][maxn];
int lev[maxn];
int a[maxn];

void addEdge(int fr, int to, int c)
{
cap[fr][to] += c;
}

//bfs找层次网络,一次寻找多条增广路径
//st最小顶点编号,ed最大顶点编号,s源点,t汇点
bool bfs(int st, int ed, int s, int t)
{
memset(lev, inf, sizeof(lev));
queue<int> q;
q.push(s);
lev[s] = 0;
while (!q.empty())
{
int t = q.front();
q.pop();
for (int i = st; i <= ed; i++)
{
if (flow[t][i] < cap[t][i])
{
if (lev[t] + 1 < lev[i])
{
lev[i] = lev[t] + 1;
q.push(i);
}
}
}
}
return lev[t] < inf;
}

//利用层次网络进行增广,每次dfs寻找的是从该点出发进行dfs增加的总量
//a表示从源点到该节点可增广流量
int dfs(int v, int st, int ed, int s, int t)
{
int res = 0;
if (v == t)
return a[t];
for (int i = st; i <= ed; i++)
{
if (a[v] == 0)
break;
if (flow[v][i] < cap[v][i] && lev[v] + 1 == lev[i])
{
a[i] = min(a[v], cap[v][i] - flow[v][i]);
int temp = dfs(i, st, ed, s, t);
res += temp;
a[v] -= temp;
flow[v][i] += temp;
flow[i][v] -= temp;
}
}
if (res == 0)
{
lev[v] = inf;
}
return res;
}

int dinic(int st, int ed, int s, int t)
{
int res = 0;
memset(flow, 0, sizeof(flow));
while (bfs(st, ed, s, t))
{
memset(a, inf, sizeof(a));
int temp = dfs(s, st, ed, s, t);
if (temp == 0)
break;
res += temp;
}
return res;
}

int main()
{
#ifdef LOCAL
freopen("in.txt", "r", stdin);
#endif // LOCAL
while (~scanf("%d%d%d", &n, &f, &d))
{
memset(cap, 0, sizeof(cap));
for (int i = 1; i <= n; i++)
{
int ft, dt;
scanf("%d%d", &ft, &dt);
while (ft--)
{
int x;
scanf("%d", &x);
addEdge(2 * n + x, i, 1);
}
while (dt--)
{
int x;
scanf("%d", &x);
addEdge(i + n, 2 * n + f + x, 1);
}
}
int s = 0, t = 2 * n + f + d + 1;
for (int i = 2 * n + 1; i <= 2 * n + f; i++)
{
addEdge(s, i, 1);
}
for (int i = 2 * n + f + 1; i <= 2 * n + f + d; i++)
{
addEdge(i, t, 1);
}
for (int i = 1; i <= n; i++)
{
addEdge(i, i + n, 1);
}
printf("%d\n", dinic(s, t, s, t));
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: