zoukankan      html  css  js  c++  java
  • 网络最大流

    不得不复习一下网络流了,先复习最大流模板吧

    最主要的就是dfs和bfs过程吧

    bfs是为了分层和判断是否需要继续

    显然对于一个图,分层之后,对于任一一边,起点要么加一等于终点,要么终点小于起点

    终点小于起点的显然已经计算过,不需要松弛()

    判断是否需要继续增广实际上是看终点是否有depth就可以解决的

    再说dfs的过程

    是通过当前的可以下放的流量dfs下去求得可以达到的流量,回溯上来统计sum,使得始终不超过限制

    详细见代码吧,其实复习了一下感觉挺简单的

    #include <iostream>
    #include <cstdio>
    #include <queue>
    #include <cstring>
    
    using namespace std;
    
    struct Edge
    {
      int to,val,next;
    }e[200010];
    
    int n,m,s,t,num;
    
    int cur[100010],head[100010],depth[100010];
    
    void addedge(int a,int b,int v)
    {
      e[num].to=b;
      e[num].next=head[a];
      e[num].val=v;
      head[a]=num++;
    }
    
    int dfs(int u,int val)//val是当前可以向前流的流量,返回的是实际流的流量
    {
      if(u==t||val==0)//如果到了终点或者没有可以继续的流量了,就return
      {
        return val;
      }
      int sum=0;//分配出去的流量
      for(int &i=cur[u];i!=-1;i=e[i].next)
      {
        if(depth[e[i].to]==depth[u]+1&&e[i].val>0)//分层图下必须要depth向下才进行,不然无意义
        {
          int f=dfs(e[i].to,min(val-sum,e[i].val));//贪心的向下一个点传输可以传输的最大的流量,返回来到底可以传多少就是下一层的事情了
          if(f>0)//如果真的传输过去了,更改当前边和反边
          {
            e[i].val-=f;
            e[i^1].val+=f;
            sum+=f;//记录分配除去的流量
            if(val==sum) return sum;//分配完了就返回
          }
        }
      }
      return sum;//返回实际分配除去的流量
    }
    
    bool bfs()//这个函数的意义在于用分层图优化时间,并且预先判断还有没有余留
    {
      memset(depth,0,sizeof(depth));//这里一定要memset
      queue <int>q;
      depth[s]=1;
      q.push(s);//塞入起点
      while(!q.empty())
      {
        int now=q.front();
        q.pop();
        for(int i=head[now];i!=-1;i=e[i].next)
        {
          if(depth[e[i].to]==0&&e[i].val>0)//如果没来到过,并且可以流过这个边
          {
            depth[e[i].to]=depth[now]+1;
            q.push(e[i].to);//继续下一层
          }
        }
      }
      return depth[t];//返回是否可以到达t
    }
    
    int main()
    {
      scanf("%d%d%d%d",&n,&m,&s,&t);
      memset(head,-1,sizeof(head));//毒瘤的反悔边让我改变了码风
      for(int i=1;i<=m;i++)
      {
        int a,b,c;
        scanf("%d%d%d",&a,&b,&c);
        addedge(a,b,c);
        addedge(b,a,0);
      }
      int ans=0;
      while(bfs())
      {
        for(int i=1;i<=n;i++)
        {
          cur[i]=head[i];//清空当前弧,如果是不能跑的边,边权已经是0了,这样反而会漏掉
        }
        ans+=dfs(s,0x3f3f3f3f);
      }
      printf("%d
    ",ans);
    }
    
    

    这里总结一下网络最大流的建模思想

    直接考察最大流

    这种一般考察很少

    最大流最小割定理

    个人认为比较重要,典型的就有三种

    1. 小行星
    2. 集合与单个的贡献矛盾
    3. 二部图的最小权点覆盖问题

    其他都差不多了

  • 相关阅读:
    Java多线程
    http网页请求状态码
    C++文件读写
    算法训练 最大的算式
    算法训练 2的次幂表示
    线段树- 算法训练 操作格子
    Prim算法(最小生成树)
    Kruskal算法(最小生成树)
    Dijkstra算法(最短路)
    HDU5692 dfs + 线段树维护区间最大值
  • 原文地址:https://www.cnblogs.com/zzqdeco/p/12821710.html
Copyright © 2011-2022 走看看