最大流&最小割&费用流模版
好久都没有搞博客了。想认真写又要准备文化课期末了。
ISAP
- 流程: 原理就是dfs找增广路。
最基础的建反向边以便反悔就不说了。
但是记录一个dep(dis)表示层数,一开始BFS(从t开始,dis[t]=0)处理最小层数,然后再搜索增广路增加限制条件:dis[u]=dis[v]+1,若这样的v找完了,扩大一层u(即dis[u]++),可能会被回溯到前面的某条新路再次搜中。然后特判一下,如果dis[s]>=n即可结束,因为dis[t]永远等于0,dis[s]最大为n-1。
gap(cnt)标记很简单:就是记录每个dis[]值的个数,若某一中间dis[]值为0,则出现了断层,理论上就搜不到增广路了。 - 代码:
#include<bits/stdc++.h>
using namespace std;
const int N=1e4+5;
const int inf=0x3f3f3f3f;
int nxt[N],to[N],head[N],len[N],num=1;
void add_edge(int u,int v,int w) {nxt[++num]=head[u];to[num]=v;len[num]=w;head[u]=num;}
int dis[N],n,m,s,t,gap[N];
void bfs()
{
memset(dis,-1,sizeof(dis));
memset(gap,0,sizeof(gap));
dis[t]=0,gap[0]=1;
queue<int>q;
q.push(t);
while(!q.empty()) {
int u=q.front();
q.pop();
for(int i=head[u];i;i=nxt[i]) {
int v=to[i];
if(dis[v]!=-1)continue;
q.push(v);
dis[v]=dis[u]+1,gap[dis[v]]++;
}
}
return;
}
long long maxflow;
long long dfs(int u,long long flow) {
if(u==t) return flow;
long long used=0;
for(int i=head[u];i;i=nxt[i]) {
int v=to[i];
if(len[i]&&dis[v]+1==dis[u]) {
int tmp=dfs(v,min(1ll*len[i],flow-used));
if(tmp) {
len[i]-=tmp;
len[i^1]+=tmp;
used+=tmp;
}
if(used==flow)return used;
}
}
--gap[dis[u]];
if(gap[dis[u]]==0)dis[s]=n;
dis[u]++,gap[dis[u]]++;
return used;
}
long long ISAP()
{
maxflow=0;
for(bfs();dis[s]<n;maxflow+=dfs(s,inf));
return maxflow;
}
int main() {
scanf("%d%d%d%d",&n,&m,&s,&t);
int u,v,w;
for(int i=1;i<=m;i++) {
scanf("%d%d%d",&u,&v,&w);
add_edge(u,v,w);
add_edge(v,u,0);
}
printf("%lld\n",ISAP());
return 0;
}
费用流算法
- 流程:
首先变化在于,找最大流的基础上满足最小(大)费用。其次,每条边上多了费用一变量,因此我们在存反边时边的费用为负的原费用
然后我们把EK_BFS找增广路改为找最短(长)路即可。注意记录前驱,最后结束时更新边信息。 - 代码:
#include<stdio.h>
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;
int mxflow=0,mnval=0,dis[N],head[N],n,m,s,t,to[N],nxt[N],len[N],val[N],ecnt=1,flow[N],pre[N],inf=0x3f3f3f3f;
void add_edge(int u,int v,int z,int w) {
nxt[++ecnt]=head[u];to[ecnt]=v;len[ecnt]=z;val[ecnt]=w;head[u]=ecnt;
nxt[++ecnt]=head[v];to[ecnt]=u;len[ecnt]=0;val[ecnt]=-w;head[v]=ecnt;
}
bool In_q[N];
queue<int> Q;
void init() {
for(int i=0;i<=n;i++)dis[i]=flow[i]=inf,In_q[i]=0,pre[i]=0;
}
bool spfa() {
init();
Q.push(s); dis[s]=0,In_q[s]=1;
while(!Q.empty()) {
int u=Q.front(); Q.pop(); In_q[s]=0;
for(int i=head[u];i;i=nxt[i]) {
int v=to[i];
if(len[i]&&dis[v]>dis[u]+val[i]) {
dis[v]=dis[u]+val[i];
flow[v]=min(flow[u],len[i]);
pre[v]=i^1; //记录终点往前的边的编号
Q.push(v),In_q[v]=1;
}
}
}
if(dis[t]==0x3f3f3f3f) return false;
return true;
}
void mn_valflow() {
while(spfa()) {
mxflow+=flow[t];
mnval+=flow[t]*dis[t];
int k=t;
while(pre[k]) {
len[pre[k]]+=flow[t],len[pre[k]^1]-=flow[t];
k=to[pre[k]];
}
}
}
int main() {
scanf("%d%d%d%d",&n,&m,&s,&t);
for(int i=1;i<=m;i++) {
int u,v,z,w;
scanf("%d%d%d%d",&u,&v,&z,&w);
add_edge(u,v,z,w);
}
mn_valflow();
printf("%d %d",mxflow,mnval);
return 0;
}
最大流&最小割&费用流模版的更多相关文章
- hdu4289 最小割最大流 (拆点最大流)
最小割最大流定理:(参考刘汝佳p369)增广路算法结束时,令已标号结点(a[u]>0的结点)集合为S,其他结点集合为T=V-S,则(S,T)是图的s-t最小割. Problem Descript ...
- 最大流-最小割 MAXFLOW-MINCUT ISAP
简单的叙述就不必了. 对于一个图,我们要找最大流,对于基于增广路径的算法,首先必须要建立反向边. 反向边的正确性: 我努力查找了许多资料,都没有找到理论上关于反向边正确性的证明. 但事实上,我们不难理 ...
- 【BZOJ-1797】Mincut 最小割 最大流 + Tarjan + 缩点
1797: [Ahoi2009]Mincut 最小割 Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 1685 Solved: 724[Submit] ...
- BZOJ-1001 狼抓兔子 (最小割-最大流)平面图转对偶图+SPFA
1001: [BeiJing2006]狼抓兔子 Time Limit: 15 Sec Memory Limit: 162 MB Submit: 14686 Solved: 3513 [Submit][ ...
- HDU(2485),最小割最大流
题目链接:http://acm.split.hdu.edu.cn/showproblem.php?pid=2485 Destroying the bus stations Time Limit: 40 ...
- 洛谷P4014 分配问题【最小/大费用流】题解+AC代码
洛谷P4014 分配问题[最小/大费用流]题解+AC代码 题目描述 有 n 件工作要分配给 n 个人做.第 i 个人做第 j 件工作产生的效益为c ij. 试设计一个将 n 件工作分配给 n 个人做的 ...
- UVA - 10480 Sabotage【最小割最大流定理】
题意: 把一个图分成两部分,要把点1和点2分开.隔断每条边都有一个花费,求最小花费的情况下,应该切断那些边.这题很明显是最小割,也就是最大流.把1当成源点,2当成汇点,问题是要求最小割应该隔断那条边. ...
- hdu1569 方格取数(2) 最大点权独立集=总权和-最小点权覆盖集 (最小点权覆盖集=最小割=最大流)
/** 转自:http://blog.csdn.net/u011498819/article/details/20772147 题目:hdu1569 方格取数(2) 链接:https://vjudge ...
- BZOJ1001:狼抓兔子(最小割最大流+vector模板)
1001: [BeiJing2006]狼抓兔子 Description 现在小朋友们最喜欢的"喜羊羊与灰太狼",话说灰太狼抓羊不到,但抓兔子还是比较在行的,而且现在的兔子还比较笨, ...
随机推荐
- es6零碎记忆
1:substring 和 substr var str = '0123456789' console.log(str.substring(1)); //123456789 console.log(s ...
- 跳转到下一页面时,必须先勾选阅读xx须知/协议才可跳转功能
当跳转到新的html页面时,先判断checkbox是否选中,选中-->跳转到新页面:未选中--弹出提示消息(请先同意须知) HTML: 1 <div class="choose& ...
- 记一次使用git报错,解决Unable to negotiate with **** port 22: no matching host key type found. Their offer: ssh-rsa
windows电脑重装系统,去官网下载了最新的git安装,一路next下来,打开bash按老路子设置,生成公钥 git config --global user.name "yourname ...
- Java---变量和基本数据类型
变量 在Java中,变量分为两种:基本类型的变量和引用类型的变量. 在Java中变量必须先定义后使用,在定义变量的时候可以给它一个初始值.如果不写初始值,默认为0或空. 变量的一个重要特点是可以重新赋 ...
- 利用 onnxruntime 库同时推理多个模型的效率研究
1. 背景 需求:针对视频形式的数据输入,对每一帧图像,有多个神经网络模型需要进行推理并获得预测结果.如何让整个推理过程更加高效,尝试了几种不同的方案. 硬件:单显卡主机. 2. 方案 由于存在多个模 ...
- 日志、第三方模块(openpyxl模块)
目录 1.日志模块 2.第三方模块 内容 日志模块 1.日志模块的主要组成部分 1.logger对象:产生日志 无包装的产品 import logging logger = logging.getLo ...
- JavaScript学习总结1-字符、数字
1.严格检查模式 JavaScript是一种十分随便自由的语言 1 <script> 2 console.log(i); 3 </script> 即使没有定义i变量,也能在控制 ...
- Go语言 文件操作
@ 目录 引言 1. 打开和关闭文件 2. 读取文件 2.1 defer 语句 2.2 手动宕机处理 2.3 打开文件并获取内容 2.4 bufio 读取文件 2.5 ioutil 读取文件 2.6 ...
- 使用aspnetcore前后端分离开发,你一定要知道这个
前言 用过Vue单页面应用开发的,一定都知道Vue-router这个路由组件,它支持hash和history两种模式. HTML5 History 模式 vue-router 默认 hash 模式 - ...
- Windows平台安装SQLite3数据库
Windows平台安装SQLite3数据库 话不多说,开始! 访问SQLite官网下载资源 在搜索引擎中键入SQLite3关键字寻找官网入口或直接点击此处前往SQLite官网,官网界面如下: 点击页面 ...