题目大意

给出一个网络图,以及其源点和汇点,求出其网络最大流。

概念

可以把网络图看作管道,节点看作管道的交界处。流就像是管道里的流水。管道有个容量(相当于横截面积),还会有个流量(相当于水流占了管道的多少横截面积)。管道的交界处的流量满足流入的流量和等于流出的流量和。网络图有源点和汇点,水流必须从源流到汇。现在要你求整个图中的最大流(也就是从源点流出的流量的最大值)。

增广路径

在当前水流流动的情况下,对于一个从源点到汇点的路径,如果组成该路径的边都没有满流,则该路径便是一个增广路径。

显然,当前图的水流流动的情况下不存在增广路径当且仅当当前图中的总流量为图的最大流。

求最大流:Dinic算法

总体思路

不断地将流量尽量大的水流注入管道,直到网络图中没有增广路径为止。

具体过程

图中每条边存储的是当前边的剩余容量。对以下操作循环:首先从源点Bfs,对当前的可增广路径进行搜索,设置每一个节点的Level。节点的Level表示水流在网络图中流经的节点的顺序。随后Dfs,根据Bfs所得的Level的顺序向当前可增广路径中注入流量尽可能大的水流。

此处有个问题,处理当前可增广路径后的水流状态不一定就是最大流的水流状态呀!所以我们还要对每一条边设置一条反向边,以达到给机会后悔的目的,其初值为0。Dfs求出当前节点的下一个节点用去的水流nextTake后,当前边剩余容量-=nextTake,其反向边的容量+=nextTake。

最后,当Bfs后,如果汇点的Level没有设置上,意味着不存在增广路径了,此时输出结果:每次循环所得的汇点流出的流量之和。

优化

对于每一个节点我们可以设置一个DfsFrom,每次Dfs时,从DfsFrom开始遍历。具体步骤看代码。注意Dfs中for括号里和循环后对DfsFrom的处理。

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std; const int MAX_NODE = 10010, MAX_EDGE = 100010 * 2, INF=0x3f3f3f3f;
#define LOOP(i, n) for(int i=1; i<=n; i++) struct Dinic
{
private:
struct Node;
struct Edge; struct Node
{
int Level, Id;
Edge *Head, *DfsFrom;
}_nodes[MAX_NODE], *Start, *Target;
int _vCount; struct Edge
{
Node *From, *To;
Edge *Next, *Rev;
int Cap;
}*_edges[MAX_EDGE];
int _eCount; Edge *NewEdge()
{
return _edges[++_eCount] = new Edge();
} Edge *AddEdge(Node *from, Node *to, int cap)
{
Edge *e = NewEdge();
e->From = from;
e->To = to;
e->Cap = cap;
e->Next = from->Head;
from->Head = e;
return e;
} bool Bfs()
{
LOOP(i, _vCount)
_nodes[i].Level = 0;
Start->Level = 1;
static queue<Node*> q;
q.push(Start);
while (!q.empty())
{
Node *cur = q.front();
q.pop();
for (Edge *e = cur->Head; e; e = e->Next)
{
if (!e->To->Level && e->Cap)
{
e->To->Level = cur->Level + 1;
q.push(e->To);
}
}
}
return Target->Level;
} int Dfs(Node *cur, int limit)
{
if (cur == Target)
return limit;
if (limit == 0)
return 0;
int curTake = 0;
for (Edge *e = cur->DfsFrom; e; e = cur->DfsFrom = e->Next)
{
if (e->Cap && e->To->Level == cur->Level + 1)
{
int nextTake = Dfs(e->To, min(limit - curTake, e->Cap));//易忘点:-curTake
e->Cap -= nextTake;
e->Rev->Cap += nextTake;
curTake += nextTake;
}
if (limit - curTake == 0)//易忘点
break;
}
return curTake;
} public:
void Build(int uId, int vId, int cap)
{
Node *u = _nodes + uId, *v = _nodes + vId;
u->Id = uId;
v->Id = vId;
Edge *e1 = AddEdge(u, v, cap), *e2 = AddEdge(v, u, 0);
e1->Rev = e2;
e2->Rev = e1;
} int Proceed()
{
int ans = 0;
while (Bfs())
{
LOOP(i, _vCount)
_nodes[i].DfsFrom = _nodes[i].Head;
ans += Dfs(Start, INF);
}
return ans;
} Dinic() {} Dinic(int totNode, int sId, int tId):_vCount(totNode),Start(_nodes+sId),Target(_nodes+tId)
{
memset(_nodes, 0, sizeof(_nodes));
memset(_edges, 0, sizeof(_edges));
} }; int main()
{
//g.Test();
#ifdef _DEBUG
freopen("c:\\noi\\source\\input.txt", "r", stdin);
#endif
int m, vCount, sId, tId;
scanf("%d%d%d%d", &vCount, &m, &sId, &tId);
static Dinic g(vCount, sId, tId);
int uId, vId, cap;
for (int i = 0; i < m; i++)
{
scanf("%d%d%d", &uId, &vId, &cap);
g.Build(uId, vId, cap);
}
int ans;
ans = g.Proceed();
printf("%d\n", ans);
}

  

luogu3376 【模板】 网络最大流的更多相关文章

  1. 【洛谷 p3376】模板-网络最大流(图论)

    题目:给出一个网络图,以及其源点和汇点,求出其网络最大流. 解法:网络流Dinic算法. 1 #include<cstdio> 2 #include<cstdlib> 3 #i ...

  2. [模板]网络最大流 & 最小费用最大流

    我的作业部落有学习资料 可学的知识点 Dinic 模板 #define rg register #define _ 10001 #define INF 2147483647 #define min(x ...

  3. P3376 [模板] 网络最大流

    https://www.luogu.org/blog/ONE-PIECE/wang-lao-liu-jiang-xie-zhi-dinic EK 292ms #include <bits/std ...

  4. P3376 【模板】网络最大流

    P3376 [模板]网络最大流 题目描述 如题,给出一个网络图,以及其源点和汇点,求出其网络最大流. 输入输出格式 输入格式: 第一行包含四个正整数N.M.S.T,分别表示点的个数.有向边的个数.源点 ...

  5. 洛谷 P3376 【【模板】网络最大流】

    题目描述 如题,给出一个网络图,以及其源点和汇点,求出其网络最大流. 输入 第一行包含四个正整数N.M.S.T,分别表示点的个数.有向边的个数.源点序号.汇点序号. 接下来M行每行包含三个正整数ui. ...

  6. 洛谷 P3376 【模板】网络最大流

    题目描述 如题,给出一个网络图,以及其源点和汇点,求出其网络最大流. 输入输出格式 输入格式: 第一行包含四个正整数N.M.S.T,分别表示点的个数.有向边的个数.源点序号.汇点序号. 接下来M行每行 ...

  7. 洛谷——P3376 【模板】网络最大流

    题目描述 如题,给出一个网络图,以及其源点和汇点,求出其网络最大流. 输入输出格式 输入格式: 第一行包含四个正整数N.M.S.T,分别表示点的个数.有向边的个数.源点序号.汇点序号. 接下来M行每行 ...

  8. P3376 【模板】网络最大流dinic算法

    P3376 [模板]网络最大流 题目描述 如题,给出一个网络图,以及其源点和汇点,求出其网络最大流. 输入输出格式 输入格式: 第一行包含四个正整数N.M.S.T,分别表示点的个数.有向边的个数.源点 ...

  9. 「LuoguP3376」 【模板】网络最大流

    题目描述 如题,给出一个网络图,以及其源点和汇点,求出其网络最大流. 输入输出格式 输入格式: 第一行包含四个正整数N.M.S.T,分别表示点的个数.有向边的个数.源点序号.汇点序号. 接下来M行每行 ...

随机推荐

  1. Kali linux 2016.2(Rolling)之 Nessus安装及Plugins Download Fail 解决方法

    最近,因科研需要,学习Nessus. Nessus是一款优秀的漏洞扫描软件,在其v6 HOME版本中在线更新漏洞插件不成功,采用离线更新,成功地更新了插件,在此将更新方法进行分享. 1.Nessus软 ...

  2. C#之MD5加密

    C#实现MD5加密 方法一 首先,先简单介绍一下MD5 MD5的全称是message-digest algorithm 5(信息-摘要算法,在90年代初由mit laboratory for comp ...

  3. webapi时间字段返回格式设置及返回model首字母小写

    GlobalConfiguration.Configuration.Formatters.Remove(new XmlMediaTypeFormatter()); // 解决json序列化时的循环引用 ...

  4. Combotree--别样的构建层级json字符串

    1.先看效果 2.需要使用层级json格式,如: 3.先不要着急怎么去实现它,先来想想怎么用对象来描述它 4.代码 protected void Page_Load(object sender, Ev ...

  5. Vue初级

    来学习vue.js的宝宝们应该都了解了什么是vue并且是有兴趣去学的,我也是自己学习vue,欢迎大家一起讨论. 现在,我么先自己尝试用vue来写个hello world吧. 一.创建一个 .html  ...

  6. bcg库使用心得两则

    作者:朱金灿 来源:http://blog.csdn.net/clever101 最近帮同事解决了两个BCG库的使用问题,特记录下来. 一是在outlook风格停靠栏上创建对话框的做法.代码如下: C ...

  7. 大型工程多个目录下的Makefile写法

    1.前言 目前从事于linux下程序开发,涉及到多个文件,多个目录,这时候编译文件的任务量比较大,需要写Makefile.关于Makefile的详细内容可以参考网上流传非常广泛的<跟我一起写Ma ...

  8. Table边框使用总结 ,只显示你要显示的边框

    表格的常用属性 基本属性有:width(宽度).height(高度).border(边框值).cellspacing(表格的内宽,即表格与tr之间的间隔). cellpadding(表格内元素的间隔, ...

  9. PKCS #1 RSA Encryption Version 1.5 填充方式

    在进行RSA运算时需要将源数据D转化为Encryption block(EB).其中pkcs1padding V1.5的填充模式安装以下方式进行 (1) EB = 00+ BT+PS +00 + D ...

  10. node、Mongo项目如何前后端分离提供接口给前端

    node接口编写,vue-cli代理接口方法  通常前端使用的MocK 数据的方法,去模拟假的数据,但是如果有node Mongodb 去写数据的话就不需要在去mock 数据了,具体的方法如下. 首先 ...