题意:

FJ准备了F种食物和D种饮料,每头牛都有喜欢的食物和饮料,并且每头牛都只能分配一种食物和饮料。问如何分配使得同时得到喜欢的食物和饮料的牛数量最多。

分析:

首先想到将牛与其对应的食物和饮料匹配起来,即在食物、饮料与牛之间连一条边,再在s和所有食物之间、t和所有饮料之间连一条边。这样每一条路径都对应着食物饮料和牛之间的匹配方案。那么如何避免一头牛被分配多组匹配呢?就将一头牛拆成两个结点,并用一条容量为1的边连接起来,这样求出构成的图中的最大流,即得解。这里使用的是Dinic算法。

代码:

#include<cstdio>
#include<vector>
#include<cstring>
#include<queue>
using namespace std;
struct edge{int to, cap, rev;};
const int maxn = 105, maxm = 2000055, INF = 0x3fffffff;
int d[maxm], iter[maxm];
int s, t;
vector<edge>G[maxm];
int dr[maxn][maxn], f[maxn][maxn];
void add_edge(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});
}
void bfs()
{
memset(d, -1, sizeof(d));
queue<int>q;
d[s] = 0;
q.push(s);
while(!q.empty()){
int v = q.front();q.pop();
for(int i = 0; i <G[v].size(); i++){
edge &e = G[v][i];
if(e.cap>0&&d[e.to]<0){
d[e.to] = d[v] + 1;
q.push(e.to);
}
}
}
}
int dfs(int v, int f)
{
if(v==t) return f;
for(int &i = iter[v]; i < G[v].size(); i++){
edge &e = G[v][i];
if(e.cap > 0 && d[v] < d[e.to]){
int tf = dfs(e.to, min(f, e.cap));
if(tf > 0){
e.cap -= tf;
G[e.to][e.rev].cap +=tf;
return tf;
}
}
}
return 0;
}
int max_flow()
{
int flow = 0;
for(;;){
bfs();
if(d[t]<0) return flow;
memset(iter, 0, sizeof(iter));
int f;
while((f = dfs(s, INF))>0){
flow += f;
}
}
}
int main (void)
{
int N, F, D;scanf("%d%d%d",&N, &F, &D);
int a, b;
s = 2 * N + F + D + 1, t = s + 1;
for(int i = 1; i <= N; i++){
scanf("%d%d",&a, &b);
add_edge(i, N + i, 1);
for(int j = 0; j < a; j++){
scanf("%d",&f[i][j]);
add_edge(2 * N + f[i][j], i, 1);
}
for(int j = 0; j < b; j++){
scanf("%d",&dr[i][j]);
add_edge(N + i, 2 * N + F + dr[i][j], 1);
}
}
for(int i = 1; i <= F; i++)
add_edge(s, 2 * N + i, 1);
for(int i = 1; i <= D; i++)
add_edge(2 * N + F + i, t, 1); printf("%d\n",max_flow());
}

增广路径必须满足的性质

1.有奇数条边。

2.起点在二分图的左半边,终点在右半边。

3.路径上的点一定是一个在左半边,一个在右半边,交替出现。(其实二分图的性质就决定了这一点,因为二分图同一边的点之间没有边相连,不要忘记哦。)

4.整条路径上没有重复的点。

5.起点和终点都是目前还没有配对的点,而其它所有点都是已经配好对的。

6.路径上的所有第奇数条边都不在原匹配中,所有第偶数条边都出现在原匹配中。

7.最后,也是最重要的一条,把增广路径上的所有第奇数条边加入到原匹配中去,并把增广路径中的所有第偶数条边从原匹配中删除(这个操作称为增广路径的取反),则新的匹配数就比原匹配数增加了1个(奇数=偶数+1)。

最新文章

  1. Redis查询当前库有多少个 key
  2. Java项目多数据源配置
  3. Mongodb Manual阅读笔记:CH3 数据模型(Data Models)
  4. Unity 依赖注入知识点
  5. C#编程总结(四)多线程应用(进度条的编程问题)——转自http://www.cnblogs.com/yank/p/3232955.html
  6. js 数组排序和算法排序
  7. .NET Framework 4.5、4.5.1 和 4.5.2 中的新增功能
  8. Yii系列教程(二):功能简介
  9. 进程和cpu的相关知识和简单调优方案
  10. Tiny6410 设备驱动之helloworld
  11. ios数据库FMDB
  12. Salt安装
  13. 008实现一个算法从一个单链表中返回倒数第n个元素(keep it up)
  14. 杭电ACM2010--水仙花数
  15. Python爬虫之正则表达式(3)
  16. Java 对远程文件的操作
  17. oracle出现无法响应新的请求,报ora-12516错误
  18. 基于PHP给大家讲解防刷票的一些技巧
  19. &lt;20190104&gt;关掉一些鸡肋的Win10功能
  20. SQLite 剖析

热门文章

  1. c#拖拽文件
  2. Java8特性之Lambda、方法引用以及Stream流
  3. Linux之测试服务器和端口连通
  4. 学习笔记 第八章 使用CSS美化列表
  5. R Programming week1-Data Type
  6. postgresql update from
  7. ORM-PetaPoco
  8. 一些常用的meta标签及其作用
  9. 洛谷 P1364 医院设置
  10. Ghost Win10系统X64位和32位10041装机版下载