最大流&最小割&费用流模版
好久都没有搞博客了。想认真写又要准备文化课期末了。
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 现在小朋友们最喜欢的"喜羊羊与灰太狼",话说灰太狼抓羊不到,但抓兔子还是比较在行的,而且现在的兔子还比较笨, ...
随机推荐
- Node的重要性
一. 为什么要学Node 1. 是自己更全面, 有大局观 2. 提升话语权 3. 升职加薪的筹码 二. Node的作用和应用 1. 脱离浏览器运行 js 2. 后台API编写 3. webpack, ...
- 小程序申请测试appid
话不多说,直接上图: 1. 登录微信官方文档: https://developers.weixin.qq.com/miniprogram/dev/devtools/sandbox.html 2. ...
- C语言-操作符与表达式
C语言入门之操作符与表达式 前言 本篇文章主要包括各种操作符的介绍与表达式求值,欢迎各位小伙伴与我一起学习. 一.操作符 分类 算术操作符 移位操作符 位操作符 赋值操作符 单目运算符 关系操作符 逻 ...
- Shiro+springboot+mybatis(md5+salt+散列)认证与授权-01
这个小项目包含了注册与登录,使用了springboot+mybatis+shiro的技术栈:当用户在浏览器登录时发起请求时,首先这一系列的请求会被拦截器进行拦截(ShiroFilter),然后拦截器根 ...
- uniapp-scroll-view纵向(竖向)滑动当scrollTop为0时卡顿问题
这个问题目前遇到的人少,所以找到答案不容易,我也是各种细节亲测才发现的解决方案.记录下来 当uniapp用scroll-view竖向滚动时,在scrollTop为0时,下拉会卡顿. 解决方法(只需要在 ...
- Blazor 修改错误提示
我们在blazor中,如果代码有异常,会产生如下的错误 在群里很多朋友都问,这个错误提示是英文的,能不能改成中文? 这个当然是可以的. 其实这个错误描述是在项目里自己定义的,具体内容可以看_Layou ...
- 『现学现忘』Git基础 — 6、Git的操作流程
目录 1.Git的基本操作流程 2.工作区.暂存区.版本库的区别 (1)工作区 (2)版本库 (3)暂存区 (4)通过新增文件理解三个区的关系 (5)说明 1.Git的基本操作流程 初始化一个本地版本 ...
- mysql学习基础2
1.什么是SQL? Structured Query Language:结构化查询语言 其实就是定义了操作所有关系型数据库的规则.每一种数据库操作的方式存在不一样的地方,称为"方言" ...
- docker基础_docker引擎内部原理
docker引擎内部原理 docker主要由以下主要组件构成:docker客户端.docker守护进程(daemon).containerd.runc.shim daemon daemon的主要功能包 ...
- Spring的3级缓存和循环引用的理解
此处是我自己的一个理解,防止以后忘记,如若那个地方理解不对,欢迎指出. 一.背景 在我们写代码的过程中一般会使用 @Autowired 来注入另外的一个对象,但有些时候发生了 循环依赖,但是我们的代码 ...