POJ 3281_Dining
2016-02-23 07:42
232 查看
题意:
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)。
相关文章推荐
- POJ 3281_Dining
- POJ 3281_Dining
- 【Android】12.3 在当前Activity中获取另一个Activity的返回值
- iOS --- 为UISlider添加点击事件
- C# 中的委托和事件
- 分析java程序中cpu占用过高的线程
- 【Android】12.2 利用Intent启动和关闭Activity
- PetaPoco 批量插入数据
- UISegmentedControl 使用
- Java网络编程的基本使用
- MVC————扩展方法MvcHtmlString
- 【Android】12.1 Intent基本概念
- 认识JSON
- 【Android】12.0 第12章 Intent及其过滤器—本章示例主界面
- day16:RDD实战(RDD基本操作实战及Transformation流程图)
- MVC————添加视图时没有模型可用
- 腾讯视频真实下载地址获取教程(一段代码即可搞定)
- 产品经理和程序员的爱恨情仇
- 细说产品经理
- EXCEL所有单元格加减乘除一个数 -- 选择性粘贴的用法