好久都没有搞博客了。想认真写又要准备文化课期末了。

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,则出现了断层,理论上就搜不到增广路了。
  • 代码:
  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. const int N=1e4+5;
  4. const int inf=0x3f3f3f3f;
  5. int nxt[N],to[N],head[N],len[N],num=1;
  6. void add_edge(int u,int v,int w) {nxt[++num]=head[u];to[num]=v;len[num]=w;head[u]=num;}
  7. int dis[N],n,m,s,t,gap[N];
  8. void bfs()
  9. {
  10. memset(dis,-1,sizeof(dis));
  11. memset(gap,0,sizeof(gap));
  12. dis[t]=0,gap[0]=1;
  13. queue<int>q;
  14. q.push(t);
  15. while(!q.empty()) {
  16. int u=q.front();
  17. q.pop();
  18. for(int i=head[u];i;i=nxt[i]) {
  19. int v=to[i];
  20. if(dis[v]!=-1)continue;
  21. q.push(v);
  22. dis[v]=dis[u]+1,gap[dis[v]]++;
  23. }
  24. }
  25. return;
  26. }
  27. long long maxflow;
  28. long long dfs(int u,long long flow) {
  29. if(u==t) return flow;
  30. long long used=0;
  31. for(int i=head[u];i;i=nxt[i]) {
  32. int v=to[i];
  33. if(len[i]&&dis[v]+1==dis[u]) {
  34. int tmp=dfs(v,min(1ll*len[i],flow-used));
  35. if(tmp) {
  36. len[i]-=tmp;
  37. len[i^1]+=tmp;
  38. used+=tmp;
  39. }
  40. if(used==flow)return used;
  41. }
  42. }
  43. --gap[dis[u]];
  44. if(gap[dis[u]]==0)dis[s]=n;
  45. dis[u]++,gap[dis[u]]++;
  46. return used;
  47. }
  48. long long ISAP()
  49. {
  50. maxflow=0;
  51. for(bfs();dis[s]<n;maxflow+=dfs(s,inf));
  52. return maxflow;
  53. }
  54. int main() {
  55. scanf("%d%d%d%d",&n,&m,&s,&t);
  56. int u,v,w;
  57. for(int i=1;i<=m;i++) {
  58. scanf("%d%d%d",&u,&v,&w);
  59. add_edge(u,v,w);
  60. add_edge(v,u,0);
  61. }
  62. printf("%lld\n",ISAP());
  63. return 0;
  64. }

费用流算法

  • 流程:

    首先变化在于,找最大流的基础上满足最小(大)费用。其次,每条边上多了费用一变量,因此我们在存反边时边的费用为负的原费用

    然后我们把EK_BFS找增广路改为找最短(长)路即可。注意记录前驱,最后结束时更新边信息。
  • 代码:
  1. #include<stdio.h>
  2. #include<bits/stdc++.h>
  3. using namespace std;
  4. const int N=1e5+5;
  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;
  6. void add_edge(int u,int v,int z,int w) {
  7. nxt[++ecnt]=head[u];to[ecnt]=v;len[ecnt]=z;val[ecnt]=w;head[u]=ecnt;
  8. nxt[++ecnt]=head[v];to[ecnt]=u;len[ecnt]=0;val[ecnt]=-w;head[v]=ecnt;
  9. }
  10. bool In_q[N];
  11. queue<int> Q;
  12. void init() {
  13. for(int i=0;i<=n;i++)dis[i]=flow[i]=inf,In_q[i]=0,pre[i]=0;
  14. }
  15. bool spfa() {
  16. init();
  17. Q.push(s); dis[s]=0,In_q[s]=1;
  18. while(!Q.empty()) {
  19. int u=Q.front(); Q.pop(); In_q[s]=0;
  20. for(int i=head[u];i;i=nxt[i]) {
  21. int v=to[i];
  22. if(len[i]&&dis[v]>dis[u]+val[i]) {
  23. dis[v]=dis[u]+val[i];
  24. flow[v]=min(flow[u],len[i]);
  25. pre[v]=i^1; //记录终点往前的边的编号
  26. Q.push(v),In_q[v]=1;
  27. }
  28. }
  29. }
  30. if(dis[t]==0x3f3f3f3f) return false;
  31. return true;
  32. }
  33. void mn_valflow() {
  34. while(spfa()) {
  35. mxflow+=flow[t];
  36. mnval+=flow[t]*dis[t];
  37. int k=t;
  38. while(pre[k]) {
  39. len[pre[k]]+=flow[t],len[pre[k]^1]-=flow[t];
  40. k=to[pre[k]];
  41. }
  42. }
  43. }
  44. int main() {
  45. scanf("%d%d%d%d",&n,&m,&s,&t);
  46. for(int i=1;i<=m;i++) {
  47. int u,v,z,w;
  48. scanf("%d%d%d%d",&u,&v,&z,&w);
  49. add_edge(u,v,z,w);
  50. }
  51. mn_valflow();
  52. printf("%d %d",mxflow,mnval);
  53. return 0;
  54. }

最大流&最小割&费用流模版的更多相关文章

  1. hdu4289 最小割最大流 (拆点最大流)

    最小割最大流定理:(参考刘汝佳p369)增广路算法结束时,令已标号结点(a[u]>0的结点)集合为S,其他结点集合为T=V-S,则(S,T)是图的s-t最小割. Problem Descript ...

  2. 最大流-最小割 MAXFLOW-MINCUT ISAP

    简单的叙述就不必了. 对于一个图,我们要找最大流,对于基于增广路径的算法,首先必须要建立反向边. 反向边的正确性: 我努力查找了许多资料,都没有找到理论上关于反向边正确性的证明. 但事实上,我们不难理 ...

  3. 【BZOJ-1797】Mincut 最小割 最大流 + Tarjan + 缩点

    1797: [Ahoi2009]Mincut 最小割 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 1685  Solved: 724[Submit] ...

  4. BZOJ-1001 狼抓兔子 (最小割-最大流)平面图转对偶图+SPFA

    1001: [BeiJing2006]狼抓兔子 Time Limit: 15 Sec Memory Limit: 162 MB Submit: 14686 Solved: 3513 [Submit][ ...

  5. HDU(2485),最小割最大流

    题目链接:http://acm.split.hdu.edu.cn/showproblem.php?pid=2485 Destroying the bus stations Time Limit: 40 ...

  6. 洛谷P4014 分配问题【最小/大费用流】题解+AC代码

    洛谷P4014 分配问题[最小/大费用流]题解+AC代码 题目描述 有 n 件工作要分配给 n 个人做.第 i 个人做第 j 件工作产生的效益为c ij. 试设计一个将 n 件工作分配给 n 个人做的 ...

  7. UVA - 10480 Sabotage【最小割最大流定理】

    题意: 把一个图分成两部分,要把点1和点2分开.隔断每条边都有一个花费,求最小花费的情况下,应该切断那些边.这题很明显是最小割,也就是最大流.把1当成源点,2当成汇点,问题是要求最小割应该隔断那条边. ...

  8. hdu1569 方格取数(2) 最大点权独立集=总权和-最小点权覆盖集 (最小点权覆盖集=最小割=最大流)

    /** 转自:http://blog.csdn.net/u011498819/article/details/20772147 题目:hdu1569 方格取数(2) 链接:https://vjudge ...

  9. BZOJ1001:狼抓兔子(最小割最大流+vector模板)

    1001: [BeiJing2006]狼抓兔子 Description 现在小朋友们最喜欢的"喜羊羊与灰太狼",话说灰太狼抓羊不到,但抓兔子还是比较在行的,而且现在的兔子还比较笨, ...

随机推荐

  1. Node的重要性

    一. 为什么要学Node 1. 是自己更全面, 有大局观 2. 提升话语权 3. 升职加薪的筹码 二. Node的作用和应用 1. 脱离浏览器运行 js 2. 后台API编写 3. webpack, ...

  2. 小程序申请测试appid

    话不多说,直接上图:  1. 登录微信官方文档: https://developers.weixin.qq.com/miniprogram/dev/devtools/sandbox.html  2. ...

  3. C语言-操作符与表达式

    C语言入门之操作符与表达式 前言 本篇文章主要包括各种操作符的介绍与表达式求值,欢迎各位小伙伴与我一起学习. 一.操作符 分类 算术操作符 移位操作符 位操作符 赋值操作符 单目运算符 关系操作符 逻 ...

  4. Shiro+springboot+mybatis(md5+salt+散列)认证与授权-01

    这个小项目包含了注册与登录,使用了springboot+mybatis+shiro的技术栈:当用户在浏览器登录时发起请求时,首先这一系列的请求会被拦截器进行拦截(ShiroFilter),然后拦截器根 ...

  5. uniapp-scroll-view纵向(竖向)滑动当scrollTop为0时卡顿问题

    这个问题目前遇到的人少,所以找到答案不容易,我也是各种细节亲测才发现的解决方案.记录下来 当uniapp用scroll-view竖向滚动时,在scrollTop为0时,下拉会卡顿. 解决方法(只需要在 ...

  6. Blazor 修改错误提示

    我们在blazor中,如果代码有异常,会产生如下的错误 在群里很多朋友都问,这个错误提示是英文的,能不能改成中文? 这个当然是可以的. 其实这个错误描述是在项目里自己定义的,具体内容可以看_Layou ...

  7. 『现学现忘』Git基础 — 6、Git的操作流程

    目录 1.Git的基本操作流程 2.工作区.暂存区.版本库的区别 (1)工作区 (2)版本库 (3)暂存区 (4)通过新增文件理解三个区的关系 (5)说明 1.Git的基本操作流程 初始化一个本地版本 ...

  8. mysql学习基础2

    1.什么是SQL? Structured Query Language:结构化查询语言 其实就是定义了操作所有关系型数据库的规则.每一种数据库操作的方式存在不一样的地方,称为"方言" ...

  9. docker基础_docker引擎内部原理

    docker引擎内部原理 docker主要由以下主要组件构成:docker客户端.docker守护进程(daemon).containerd.runc.shim daemon daemon的主要功能包 ...

  10. Spring的3级缓存和循环引用的理解

    此处是我自己的一个理解,防止以后忘记,如若那个地方理解不对,欢迎指出. 一.背景 在我们写代码的过程中一般会使用 @Autowired 来注入另外的一个对象,但有些时候发生了 循环依赖,但是我们的代码 ...