P3376 【模板】网络最大流(luogu)

最大流的dinic算法模板(采取了多种优化)

优化 时间
inline+当前弧+炸点+多路增广 174ms
no 当前弧 175ms
no 炸点 249

自己对最大流算法的理解:

通过bfs对剩余图进行分层,剩余图中有流量的边(cap>0)才能bfs,然后dfs找增广路(满足dis[v]==dis[u]+1&&cap(u,v)>0)

各种优化(基本是在dfs(s,flow)上做的)的实现思路:

  • 多路增广

    通过记录从s流出的各个边增广的和,而不是找到目标t就返回(可以比较一下两段代码
  1. //当前弧优化效果不明显可不加
  2. struct Edge{
  3. int v,nxt,cap;
  4. }es[maxm];
  5. void add(int u,int v,int cap){
  6. //printf("db add %d->%d %d\n",u,v,cap);
  7. es[cnt].v=v,es[cnt].cap=cap,es[cnt].nxt=head[u];
  8. head[u]=cnt,cnt++;
  9. }
  10. int bfs(int s,int des){
  11. CL(dep,-1);
  12. queue<int> q;q.push(s);
  13. dep[s]=1;
  14. while(!q.empty()){
  15. int tmp=q.front();q.pop();
  16. for(int t=head[tmp];t!=-1;t=es[t].nxt){
  17. int v=es[t].v,cap=es[t].cap;
  18. if(cap>0&&dep[v]==-1){//dep[v]==-1代表未访问过
  19. dep[v]=dep[tmp]+1;q.push(v);
  20. if(v==des) return 1;
  21. }
  22. }
  23. }
  24. return dep[des]>-1?1:0;//是否能到达目的节点
  25. }
  26. int dfs(int s,int fl,int des){//fl流入s的流量,向s的出边增光
  27. if(s==des||fl<=0) return fl;
  28. int res=0; //多路增光
  29. for(int t=head[s];fl&&t!=-1;t=es[t].nxt){
  30. int v=es[t].v,cap=es[t].cap;
  31. if(dep[v]==dep[s]+1){
  32. int f=dfs(v,min(fl,cap),des);
  33. es[t].cap-=f,es[t^1].cap+=f,res+=f;
  34. fl-=f;
  35. }
  36. }
  37. if(res==0) dep[s]=-2;//炸点优化
  38. return res;
  39. }

所以朴素的方式往往需要一次bfs,多次dfs;而经过多路扩展则是一次bfs,一次dfs(因为一次dfs就找全了所有增广路)

  • 当前弧优化

    思想是记录节点s应该流向的边,假设有这样s->1,s->2,s->3假设s->2时流量flow已经耗尽,那么下一次从3流出的应该从s->2开始(注意流向s可能有多条路径,flow只是流向s的某一条路径的流量)
  1. for(int x=cur[s];x!=-1;x=e[x].next){
  2. cur[s]=x;//当前弧优化
  3. if(d[e[x].v]==d[s]+1&&e[x].cap>0){
  4. //....
  5. if(!flow) break;//当前已经没有流量
  6. }
  7. }
  • 炸点优化

    一个非目的点,流不出任何流量,那么以后都不用向该点流,所以d[s]=-2(以后dfs都不会流向它)

代码

  1. //dinic 算法处理最大流问题
  2. #include<bits/stdc++.h>
  3. using namespace std;
  4. #define inf 0x3f3f3f3f
  5. const int maxn=1e4+10;
  6. const int maxm=1e5+10;
  7. int s,t,n,m;
  8. struct Edge{
  9. int v,next,cap;
  10. }e[maxm<<1];// begin from 0
  11. int head[maxn];//-1 init
  12. int cnt=-1;
  13. int d[maxn];//init inf
  14. int que[maxn<<2];
  15. int cur[maxn];//for 当前弧优化
  16. inline void add(int u,int v,int cap){//边从0开始
  17. //e[cnt]=(Edge){v,head[u],cap};
  18. cnt++;
  19. e[cnt].v=v,e[cnt].next=head[u],e[cnt].cap=cap;
  20. head[u]=cnt;
  21. }
  22. inline bool bfs(int ss,int tt){
  23. memset(d,inf,sizeof(d));
  24. memcpy(cur,head,sizeof(head));
  25. int h=0,t=1;
  26. que[0]=ss,d[ss]=1;
  27. while(t>h){
  28. int u=que[h];
  29. h++;
  30. for(int x=head[u];x!=-1;x=e[x].next){
  31. int v=e[x].v;
  32. if(d[v]>=inf&&e[x].cap>0){
  33. d[v]=d[u]+1;//d[]用作vis[]
  34. que[t++]=v;
  35. }
  36. }
  37. }
  38. //printf("db %d\n",d[tt]);
  39. return d[tt]<inf;
  40. }
  41. inline int dfs(int s,int flow){
  42. if(s==t||flow<=0) return flow;
  43. int res=0;
  44. for(int x=cur[s];x!=-1;x=e[x].next){
  45. cur[s]=x;//当前弧优化
  46. if(d[e[x].v]==d[s]+1&&e[x].cap>0){
  47. int f=dfs(e[x].v,min(flow,e[x].cap));
  48. e[x].cap-=f;
  49. e[x^1].cap+=f;
  50. res+=f;//通过res记录多路扩展
  51. flow-=f;
  52. if(!flow) break;//当前已经没有流量
  53. }
  54. }
  55. if(!res) d[s]=-2;//炸点优化,s没能流出任何流量,那么本次bfs下的dfs无需再向s流
  56. return res;
  57. }
  58. inline void dbgraph(){
  59. for(int i=1;i<=n;i++){
  60. printf("%d:",i);
  61. for(int x=head[i];x!=-1;x=e[x].next){
  62. if(e[x].cap>0) printf("%d\t",e[x].v);
  63. }
  64. printf("\n");
  65. }
  66. }
  67. int main(){
  68. //freopen("in.txt","r",stdin);
  69. scanf("%d %d %d %d",&n,&m,&s,&t);
  70. memset(head,-1,sizeof(head));
  71. for(int i=1;i<=m;i++){
  72. int u,v,cap;
  73. scanf("%d %d %d",&u,&v,&cap);
  74. add(u,v,cap);
  75. add(v,u,0);
  76. }
  77. //dbgraph();
  78. int ans=0;
  79. while(bfs(s,t)){
  80. //printf("in bfs\n");
  81. ans+=dfs(s,inf);
  82. }
  83. printf("%d\n",ans);
  84. //fclose(stdin);
  85. return 0;
  86. }

补充一点

从EK算法到Dinic算法有很重要的原因在于下面一张图

P3376 【模板】网络最大流(luogu)的更多相关文章

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

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

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

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

  3. 【Luogu P3376】网络最大流

    Luogu P3376 最大流是网络流模型的一个基础问题. 网络流模型就是一种特殊的有向图. 概念: 源点:提供流的节点(入度为0),类比成为一个无限放水的水厂 汇点:接受流的节点(出度为0),类比成 ...

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

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

  5. Dinic最大流 || Luogu P3376 【模板】网络最大流

    题面:[模板]网络最大流 代码: #include<cstring> #include<cstdio> #include<iostream> #define min ...

  6. luogu P3376 【模板】网络最大流(no)ek

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

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

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

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

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

  9. 『题解』洛谷P3376 【模板】网络最大流

    Problem Portal Portal1:Luogu Description 如题,给出一个网络图,以及其源点和汇点,求出其网络最大流. Input 第一行包含四个正整数\(N,M,S,T\),分 ...

随机推荐

  1. ubuntu重置root密码(转载自https://zhinan.sogou.com/guide/detail/?id=316512881651)

    ubuntu忘记root密码怎么办?如果普通用户忘记了怎么办 ### 第一种方法:无论你是否申请了root帐号,或是普通账号密码忘记了都没有问题的! 1. 重启ubuntu,随即长按shift进入gr ...

  2. HDU2147 - kiki's game 【巴什博弈】

    Recently kiki has nothing to do. While she is bored, an idea appears in his mind, she just playes th ...

  3. FreeMarker 页面静态化解决方案

    一.网页的静态化方案 1.生成静态页面的时机:在做添加操作时,同时生成该新增内容的对应的静态页面 2.静态页面的名称:内容 id + ".html" 3.静态页面所在的路径:工程外 ...

  4. redis 零散知识

    1.单线程 2.默认 16 个库.0~15 3.select :切换数据库 4.DBsize :查看当前数据库的数量 5.keys * :查看当前库的所有 key 6.keys k? :问号是占位符 ...

  5. Mysql 下DELETE操作表别名问题

    在用DELETE删除mysql数据库数据时采取一下两种方式: 方式一:DELETE FROM B_PROSON WHERE ID = 1; 不使用别名 方式二:DELETE BP FROM B_PRO ...

  6. 组件的使用(三)AutoCompleteTextView的使用

    AutoCompleteTextView经常使用的属性: android:completionHint 下拉列表以下的说明性文字 android:completionThreshold 弹出下来列表的 ...

  7. SwipeRefreshLayout与ViewPager滑动事件冲突解决

    问题描写叙述: 开发中发现,SwipeRefreshLayout的下拉刷新,与ViewPager开发的banner的左右滑动事件有一点冲突,导致banner的左右滑动不够顺畅. 非常easy在bann ...

  8. UVA 10196 Morning Walk(欧拉回路)

    Problem H Morning Walk Time Limit 3 Seconds Kamalis a Motashotaguy. He has got a new job in Chittago ...

  9. 关于wait notify notifyall的学习心得

    wait()能让同步的线程挂起并将锁抛出,sleep只能使线程“睡了“,线程的锁并不会抛出,所以sleep还可以作用于非同步的线程.notify与notifyall能将被挂起或睡着的线程唤醒,但并不是 ...

  10. linux下使用convert命令修改图片分辨率【转】

    本文转载自:http://blog.csdn.net/mybelief321/article/details/9969949 Convert的resize子命令应该是在ImageMagick中使用较多 ...