最大网络流dinic
- 初始化flow(最大流量)为INF(极大值),建边(正向弧和反向弧)
- bfs寻找增广路看看有没有路,顺便进行深度标号。如果没有路直接结束输出flow。
- 如果有,我们按照深度dfs。dfs时注意在给正向弧减权时给反向弧加权。
- ans+=flow,重复2到4步骤,直到无路可走。
- 输出结束~
以上就是网络流全部内容(误
概念什么的就不讲啦~
下面来仔细分析板子代码。
- 初始化ans=0,构建边
- dinic中心:
while(BFS()) ans+=DFS(start,INF);
- BFS:
inline bool BFS()
{
memset(dep,-1,sizeof dep);
//每次BFS更新深度,-1代表未被更新或者无路径访问
dep[s]=0;
//起点的深度为0
q.push(s);
while(!q.empty())
{
int u=q.front();q.pop();
for(R int i=head[u];i;i=e[i].nxt)
if(e[i].dis and dep[e[i].to]==-1)//一定有流并且未被访问
dep[e[i].to]=dep[u]+1,q.push(e[i].to);
}
if(dep[end]==-1)return 0;//如果end的深度为-1,无路径到达,此时最大流
return 1;
}
- DFS
ll DFS(int x,ll flow)
{
if(x==end) return flow;//到终点就返回流
ll used=0;//优化,记录已用过的流
for(R int i=head[x];i;i=e[i].nxt)
{
int u=e[i].to;
if(e[i].dis and dep[u]==dep[x]+1)
{
long long w=DFS(u,min(e[i].dis,flow-used));//求出最大流
used+=w;
e[i].dis-=w;e[i^1].dis+=w;//i^1为相反方向的边,对应加权
if(used==flow)return flow;
}
}
if(!used)dep[x]=-1;//无流可走,说明此点已经无意义了
return used;//最大流
}
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
#define R register
#define INF 1<<30
using namespace std;
template <typename T>
inline T read()
{
T x=0;int w=0;char c=getchar();
while(!isdigit(c))w|=c=='-',c=getchar();
while(isdigit(c))x=(x<<3)+(x<<1)+(c^48),c=getchar();
return w?-x:x;
}
namespace ysr
{
typedef long long ll;
const int maxn=100000;
struct Edge{
int to,nxt;
ll dis;
}e[200000];
int cur[maxn],head[maxn],ecnt=1;//这里记为-1的原因时便于访问正向弧和反向弧
int n,m,s,end,dep[maxn];
inline void addedge(int from,int to,ll dis){
e[++ecnt].to=to,e[ecnt].nxt=head[from],e[ecnt].dis=dis,head[from]=ecnt;
}
inline void add(int from,int to,ll dis){
addedge(from,to,dis);addedge(to,from,0);
}
ll DFS(int x,ll flow)
{
if(x==end) return flow;
ll used=0;
for(R int i=head[x];i;i=e[i].nxt)
{
int u=e[i].to;
if(e[i].dis and dep[u]==dep[x]+1)
{
long long w=DFS(u,min(e[i].dis,flow-used));
used+=w;
e[i].dis-=w;e[i^1].dis+=w;
if(used==flow)return flow;
}
}
if(!used)dep[x]=-1;
return used;
}
queue<int>q;
inline bool BFS()
{
memset(dep,-1,sizeof dep);
dep[s]=0;
q.push(s);
while(!q.empty())
{
int u=q.front();q.pop();
for(R int i=head[u];i;i=e[i].nxt)
if(e[i].dis and dep[e[i].to]==-1)
dep[e[i].to]=dep[u]+1,q.push(e[i].to);
}
if(dep[end]==-1)return 0;
return 1;
}
inline void work()
{
n=read<int>(),m=read<int>(),s=read<int>(),end=read<int>();
ll ans=0;
int a,b;
ll c;
for(R int i=0;i<m;i++)a=read<int>(),b=read<int>(),c=read<ll>(),add(a,b,c);
while(BFS())
ans+=DFS(s,INF);
printf("%lld\n",ans);
}
}
signed main()
{
ysr::work();
return 0;
}
大家一定已经发现我定义了一个cur数组不知道但什么的。这其实就是【当前弧优化】的数组,虽然我在上面没有使用。
这也不是什么高深的玩意。我们证明,如果一个点在之前的dfs中已经把一些边考虑过了,由于在当前和以后的流的dfs中这些边都是增广过的,也就是再也没法做出贡献了,那么我们用一个数组cur记录一下考虑到哪里了然后下一侧dfs时接着上次的就行了。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
#define R register
#define INF 1<<30
using namespace std;
template <typename T>
inline T read()
{
T x=0;int w=0;char c=getchar();
while(!isdigit(c))w|=c=='-',c=getchar();
while(isdigit(c))x=(x<<3)+(x<<1)+(c^48),c=getchar();
return w?-x:x;
}
namespace ysr
{
typedef long long ll;
const int maxn=100000;
struct Edge{
int to,nxt;
ll dis;
}e[200000];
int cur[maxn],head[maxn],ecnt=1;//这里记为-1的原因时便于访问正向弧和反向弧
int n,m,s,end,dep[maxn];
inline void addedge(int from,int to,ll dis){
e[++ecnt].to=to,e[ecnt].nxt=head[from],e[ecnt].dis=dis,head[from]=ecnt;
}
inline void add(int from,int to,ll dis){
addedge(from,to,dis);addedge(to,from,0);
}
ll DFS(int x,ll flow)
{
if(x==end) return flow;
ll used=0;
for(R int i=cur[x];i;i=e[i].nxt)
{
cur[x]=i;
int u=e[i].to;
if(e[i].dis and dep[u]==dep[x]+1)
{
long long w=DFS(u,min(e[i].dis,flow-used));
used+=w;
e[i].dis-=w;e[i^1].dis+=w;
if(used==flow)return flow;
}
}
if(!used)dep[x]=-1;
return used;
}
queue<int>q;
inline bool BFS()
{
for(R int i=0;i<=n;i++)cur[i]=head[i],dep[i]=-1;
dep[s]=0;
q.push(s);
while(!q.empty())
{
int u=q.front();q.pop();
for(R int i=head[u];i;i=e[i].nxt)
if(e[i].dis and dep[e[i].to]==-1)
dep[e[i].to]=dep[u]+1,q.push(e[i].to);
}
if(dep[end]==-1)return 0;
return 1;
}
inline void work()
{
n=read<int>(),m=read<int>(),s=read<int>(),end=read<int>();
ll ans=0;
int a,b;
ll c;
for(R int i=0;i<m;i++)a=read<int>(),b=read<int>(),c=read<ll>(),add(a,b,c);
while(BFS())
ans+=DFS(s,INF);
printf("%lld\n",ans);
}
}
signed main()
{
ysr::work();
return 0;
}
还是模板
最大网络流dinic的更多相关文章
- POJ 1273 Drainage Ditches (网络流Dinic模板)
Description Every time it rains on Farmer John's fields, a pond forms over Bessie's favorite clover ...
- ACM/ICPC 之 有流量上下界的网络流-Dinic(可做模板)(POJ2396)
//有流量上下界的网络流 //Time:47Ms Memory:1788K #include<iostream> #include<cstring> #include<c ...
- 网络流Dinic(本篇介绍最大流)
前言:看到网上Dinic和ISAP的比较,多数人认为ISAP更快,不容易爆栈.当然,也有少数人认为,在多数情况下,Dinic比较稳定.我认为Dinic的思路比ISAP更简明,所以选择了Dinc算法 介 ...
- 模板——网络流Dinic
感谢这位大佬的博客:https://www.cnblogs.com/SYCstudio/p/7260613.html 给予了我莫大的帮助! 主要说一下网络流的几个注意点: 1.和二分图匹配相似,无法继 ...
- 网络流dinic实现总结
太羞耻了,搞了半天居然没发现自己写的不是dinic,直到被一道时限紧的题目卡掉才发现 int dfs(int now,int flow,int sum) { if(now==n) return flo ...
- poj 1459 Power Network : 最大网络流 dinic算法实现
点击打开链接 Power Network Time Limit: 2000MS Memory Limit: 32768K Total Submissions: 20903 Accepted: ...
- POJ 1273 Drainage Ditches(网络流dinic算法模板)
POJ 1273给出M条边,N个点,求源点1到汇点N的最大流量. 本文主要就是附上dinic的模板,供以后参考. #include <iostream> #include <stdi ...
- 高效的网络流dinic算法模版
#include <cstring> #include <algorithm> #include <vector> #define Maxn 120010 #def ...
- 网络流(dinic算法)
网络最大流(dinic) 模型 在一张图中,给定一个源点s,给定汇点t,点之间有一些水管,每条水管有一个容量,经过此水管的水流最大不超过容量,问最大能有多少水从s流到t(s有无限多的水). 解法 di ...
随机推荐
- 采用MVC模式创建一个简单的javascript App
初次翻译,翻译的不好,还请见谅 JavaScript中最好的一部分之一,也可能是最糟糕的. 在HTML文档的头部添加一个开始和结束脚本标记,并在其中引入一些意大利面条式的代码,毫无疑问这是一种过分简单 ...
- Spring Security 快速上手
Spring Security 框架简介 Spring Security 说明 Spring Security 基于 Spring 框架,提供了一套 Web 应用安全性的完整解决方案 关于安全方面的两 ...
- UF_LAYOUT 布局相关
Open C uc6460uc6462uc6463uc6464 根据视图名称旋转视图,在布局中替换视图uc6466uc6467uc6468uc6469uc6470uc6471uc6472uc6473
- 使用mockjs模拟分页请求
首先安装mockjs npm install mockjs --save-dev 创建mock.js //mock.js const Mock = require("mockjs" ...
- JNI相关笔记 [TOC]
JNI相关笔记 目录 JNI相关笔记 1 生成native code所需要的头文件 2 JNI提供的一些函数和方法 3 局部引用,全局引用,全局弱引用. 4 异常 1 生成native code所需要 ...
- 555定时器(1)单稳态触发器电路及Multisim实例仿真
555定时器(Timer)因内部有3个5K欧姆分压电阻而得名,是一种多用途的模数混合集成电路,它能方便地组成施密特触发器.单稳态触发器与多谐振荡器,而且成本低,性能可靠,在各种领域获得了广泛的应用. ...
- 快速串讲——JVM内存的区域划分
目的 快速定位JVM内存泄漏或者溢出等问题. 面试基础题,加分项. 文章持续更新,微信搜索「万猫学社」第一时间阅读,关注后回复「电子书」,免费获取12本Java必读技术书籍. 程序计数器(Progra ...
- 使用jsonp实现跨源请求
jsonp 该技术用来实现跨源请求,即向协议.域名.端口号不同的服务器发送请求 通过使用 script 标签的 src 向服务器发送GET请求http://xxx/xxx?callback=callb ...
- Docker:Docker部署postgresql数据库
环境 Centos-7 Postgresql-10 docker-19 yum加载Postgresql yum install https://download.postgresql.org/pub ...
- log4j和log4j2的配置部分
log4j和log4j2的功能及形式对比 http://blog.csdn.net/fangaohua200/article/details/53561718 log4j2的proptise配置 ht ...