网络流 之 dinic算法
我觉得这个dinic的算法和之前的增广路法差不多
、使用BFS对残余网络进行分层,在分层时,只要进行到汇点的层次数被算出即可停止,
因为按照该DFS的规则,和汇点同层或更下一层的节点,是不可能走到汇点的。 、分完层后,从源点开始,用DFS从前一层向后一层反复寻找增广路(即要求DFS的每一步都必须要走到下一层的节点)。 、DFS过程中,要是碰到了汇点,则说明找到了一条增广路径。此时要增加总流量的值,消减路径上各边的容量,
并添加反向边,即所谓的进行增广。 、DFS找到一条增广路径后,并不立即结束,而是回溯后继续DFS寻找下一个增广路径。回溯到的结点满足以下的条件: ) DFS搜索树的树边(u,v)上的容量已经变成0。即刚刚找到的增广路径上所增加的流量,等于(u,v)本次增广前的容量。
(DFS的过程中,是从u走到更下层的v的)
) u是满足条件 )的最上层的节点。 、如果回溯到源点而且无法继续往下走了,DFS结束。因此,一次DFS过程中,可以找到多条增广路径。
、DFS结束后,对残余网络再次进行分层,然后再进行DFS当残余网络的分层操作无法算出汇点的层次(即BFS到达不了汇点)时,
算法结束,最大流求出。 #include <cstdio>
#include <cstdlib>
#include <vector>
#include <queue>
#define INF 0x3f3f3f3f
using namespace std;
const int maxn = 1e5;
struct edge
{
int u, v, c, f;
edge(int u, int v, int c, int f) :u(u), v(v), c(c), f(f) {}
};
vector<edge>e;
vector<int>G[maxn];
int level[maxn];//BFS分层,表示每个点的层数
int iter[maxn];//当前弧优化
int m;
void init(int n)
{
for (int i = ; i <= n; i++)G[i].clear();
e.clear();
}
void addedge(int u, int v, int c)
{
e.push_back(edge(u, v, c, ));
e.push_back(edge(v, u, , ));
m = e.size();
G[u].push_back(m - );
G[v].push_back(m - );
}
void BFS(int s)//预处理出level数组
//直接BFS到每个点
{
memset(level, -, sizeof(level));
queue<int>q;
level[s] = ;
q.push(s);
while (!q.empty())
{
int u = q.front();
q.pop();
for (int v = ; v < G[u].size(); v++)
{
edge& now = e[G[u][v]];
if (now.c > now.f && level[now.v] < )
{
level[now.v] = level[u] + ;
q.push(now.v);
}
}
}
}
int dfs(int u, int t, int f)//DFS寻找增广路
{
if (u == t)return f;//已经到达源点,返回流量f
for (int &v = iter[u]; v < G[u].size(); v++)
//这里用iter数组表示每个点目前的弧,这是为了防止在一次寻找增广路的时候,对一些边多次遍历
//在每次找增广路的时候,数组要清空
{
edge &now = e[G[u][v]];
if (now.c - now.f > && level[u] < level[now.v])
//now.c - now.f > 0表示这条路还未满
//level[u] < level[now.v]表示这条路是最短路,一定到达下一层,这就是Dinic算法的思想
{
int d = dfs(now.v, t, min(f, now.c - now.f));
if (d > )
{
now.f += d;//正向边流量加d
e[G[u][v] ^ ].f -= d;
//反向边减d,此处在存储边的时候两条反向边可以通过^操作直接找到
return d;
}
}
}
return ;
}
int Maxflow(int s, int t)
{
int flow = ;
for (;;)
{
BFS(s);
if (level[t] < )return flow;//残余网络中到达不了t,增广路不存在
memset(iter, , sizeof(iter));//清空当前弧数组
int f;//记录增广路的可增加的流量
while ((f = dfs(s, t, INF)) > )
{
flow += f;
}
}
return flow;
}
接下来贴一个模板题,但是这个题目的图有点难建
C - Dining
Cows are such finicky eaters. Each cow has a preference for certain foods and drinks, and she will consume no others.
Farmer John has cooked fabulous meals for his cows, but he forgot to check his menu against their preferences. Although he might not be able to stuff everybody, he wants to give a complete meal of both food and drink to as many cows as possible.
Farmer John has cooked F (1 ≤ F ≤ 100) types of foods and prepared D (1 ≤ D ≤ 100) types of drinks. Each of his N (1 ≤ N ≤ 100) cows has decided whether she is willing to eat a particular food or drink a particular drink. Farmer John must assign a food type and a drink type to each cow to maximize the number of cows who get both.
Each dish or drink can only be consumed by one cow (i.e., once food type 2 is assigned to a cow, no other cow can be assigned food type 2).
Input
Lines 2.. N+1: Each line i starts with a two integers Fi and Di, the number of dishes that cow i likes and the number of drinks that cow i likes. The next Fiintegers denote the dishes that cow i will eat, and the Di integers following that denote the drinks that cow i will drink.
Output
Sample Input
4 3 3
2 2 1 2 3 1
2 2 2 3 1 2
2 2 1 3 1 2
2 1 1 3 3
Sample Output
3
Hint
Cow 1: no meal
Cow 2: Food #2, Drink #2
Cow 3: Food #1, Drink #1
Cow 4: Food #3, Drink #3
The pigeon-hole principle tells us we can do no better since there are only three kinds of food or drink. Other test data sets are more challenging, of course.
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <queue>
#include <cstring>
#include <vector>
#define inf 0x3f3f3f3f
using namespace std;
const int maxn = 1e5 + ;
int n, f, d;
struct node
{
int from, to, cap, flow;
node(int from = , int to = , int cap = , int flow = ) :from(from), to(to), cap(cap), flow(flow) {}
};
vector<node>e;
vector<int>G[maxn];
int level[maxn], iter[maxn];
void add(int u, int v, int w)
{
e.push_back(node(u, v, w, ));
e.push_back(node(v, u, , ));
int m = e.size();
G[u].push_back(m - );
G[v].push_back(m - );
} void bfs(int s)//这个是为了构建层次网络,也就是level的构建
{
memset(level, -, sizeof(level));
queue<int>que;
que.push(s);
level[s] = ;
while (!que.empty())
{
int u = que.front(); que.pop();
for (int i = ; i < G[u].size(); i++)
{
node &now = e[G[u][i]];
if (now.cap > now.flow&&level[now.to] < )//只有这个没有满并且没有被访问过才可以被访问
{
level[now.to] = level[u] + ;
que.push(now.to);
}
}
}
} int dfs(int u, int v, int f)
{
if (u == v) return f;
for (int &i = iter[u]; i < G[u].size(); i++)
{
node &now = e[G[u][i]];
if (now.cap > now.flow&&level[now.to] > level[u])
{
int d = dfs(now.to, v, min(f, now.cap - now.flow));
if (d > )
{
now.flow += d;
e[G[u][i] ^ ].flow -= d;
return d;
}
}
}
return ;
} int Maxflow(int s, int t)
{
int flow = ;
while ()
{
bfs(s);
if (level[t] < ) return flow;
memset(iter, , sizeof(iter));
int f;
while ((f = dfs(s, t, inf) > )) flow += f;
}
}
void init()
{
for (int i = ; i <= n + ; i++) G[i].clear();
e.clear();
} int main()
{
while (cin >> n >> f >> d)
{
init();
int s = , t = f + * n + d + ;
for (int i = ; i <= f; i++) add(s, i, );
for (int i = ; i <= n; i++)
{
int a, b;
cin >> a >> b;
while (a--)//与牛i相连
{
int x;
cin >> x;
add(x, f + i, );
}
add(f + i, f + n + i, );
while (b--)
{
int x;
cin >> x;
add(f + n + i, f + * n + x, );
}
}
for (int i = ; i <= d; i++) add(f + * n + i, t, );
int ans = Maxflow(s, t);
cout << ans << endl;
}
return ;
}
网络流 之 dinic算法的更多相关文章
- [知识点]网络流之Dinic算法
// 此博文为迁移而来,写于2015年2月6日,不代表本人现在的观点与看法.原始地址:http://blog.sina.com.cn/s/blog_6022c4720102vrg4.html ...
- [无效]网络流之Dinic算法
// 此博文为迁移而来,写于2015年2月6日,不代表本人现在的观点与看法.原始地址:http://blog.sina.com.cn/s/blog_6022c4720102vrg4.html UPDA ...
- 网络流之Dinic算法
初学网络流.存一下Dinic板子. 复杂度O(n^2*m) UVA - 1515 Pool construction 把每个草地与 S 相连,花费为dig,每个洞与 T 相连,花费为 然后对于每个两个 ...
- 网络流 之 dinic 算法
网络流指的是:网络流(network-flows)是一种类比水流的解决问题方法.(类似于水管群,有一个源点(水无限多),和一个汇点,最大流就代表这个点水管群(边集)每秒最大能送道汇点的水量) 这个怎么 ...
- Secret Milking Machine POJ - 2455 网络流(Dinic算法---广搜判断+深搜增广)+时间优化+二分
题意: 第一行输入N M C ,表示从1到N有M条无向边,现在要从1走到N 走C次完全不同的路径,求最长边的最小值.下面M行是从a点到b点的距离. 建图: 题上说从两点之间可以有多条边,问的是从1~N ...
- 网络流(dinic算法)
洛谷p3376 https://www.luogu.com.cn/problem/P3376 #include <iostream> #include <cstdio> #in ...
- 网络流最大流——dinic算法
前言 网络流问题是一个很深奥的问题,对应也有许多很优秀的算法.但是本文只会讲述dinic算法 最近写了好多网络流的题目,想想看还是写一篇来总结一下网络流和dinic算法以免以后自己忘了... 网络流问 ...
- 网络流入门—用于最大流的Dinic算法
"网络流博大精深"-sideman语 一个基本的网络流问题 最早知道网络流的内容便是最大流问题,最大流问题很好理解: 解释一定要通俗! 如右图所示,有一个管道系统,节点{1,2,3 ...
- Dinic算法(研究总结,网络流)
Dinic算法(研究总结,网络流) 网络流是信息学竞赛中的常见类型,笔者刚学习了最大流Dinic算法,简单记录一下 网络流基本概念 什么是网络流 在一个有向图上选择一个源点,一个汇点,每一条边上都有一 ...
随机推荐
- AngularJS7那些不得不说的事故
题外话 最近简直要忙死,所以停更了很久,你们会不会以为我人间蒸发了? 正文之前,请允许我先跑个题,就是关于忙的问题. 做了Freelance,每天过的比上班还累,这完全不是我想要的生活啊? ...
- 从锅炉工到AI专家(7)
说说计划 不知不觉写到了第七篇,理一下思路: 学会基本的概念,了解什么是什么不是,当前的位置在哪,要去哪.这是第一篇希望做到的.同时第一篇和第二篇的开始部分,非常谨慎的考虑了非IT专业的读者.希望借此 ...
- eclipse连接Android8.0以上手机无法打印日志的问题
概述 我的eclipse的环境: Eclipse:Eclipse IDE for Java DevelopersVersion: Luna Service Release 2 (4.4.2) Andr ...
- PerformanceCounter蛋痛的设计
在.NET下对进程的性能计数可以使用PerformanceCounter,通过该对象可以对进程的CPU,内存等信息进行统计.对于正常使用来说这个对象还是很方便,但对于同一名称的多个进程进行性能计数那真 ...
- java中用MessageFormat格式化json字符串用占位符时出现的问题can't parse argument number
在MessageFormat.format方法中组装jason数据字符串:{code:"w1",des:"w2"},起止分别有左大括号和右大括号. 直接写的点位 ...
- leetcode — best-time-to-buy-and-sell-stock-ii
/** * Source : https://oj.leetcode.com/problems/best-time-to-buy-and-sell-stock-ii/ * * * * Say you ...
- 为容器化的 Go 程序搭建 CI
本文介绍如何使用 Jenkins 的声明式 pipeline 为一个简单的 Golang web 应用搭建 CI 环境.如果你还不太了解 Jenkins 及其声明式 pipeline,请先参考笔者的 ...
- Docker Compose 原理
Docker 的优势非常明显,尤其是对于开发者来说,它提供了一种全新的软件发布机制.也就是说使用 docker 镜像作为软件产品的载体,使用 docker 容器提供独立的软件运行上下文环境,使用 do ...
- SpringBoot整合系列-PageHelper分页插件
原创作品,可以转载,但是请标注出处地址:https://www.cnblogs.com/V1haoge/p/9971043.html SpringBoot整合MyBatis分页插件PageHelper ...
- 修复UEFI模式下Manjaro Linux启动问题
上周在更新Manjaro Linux的时候误触了电源键,导致内核更新了一半系统强制关机,重启时正常进入grub但无法正常引导进入系统. 由于不想重装系统(一大堆环境和工具的配置还是相当繁琐的),加上初 ...