网络流理解与模板

对于最大流与最大流等于最小割的理解
参考某大佬博客:

EK求最大流模板:

#include<bits/stdc++.h>
using namespace std;
const int N=1e3+10,M=2e4+10,INF=0x3f3f3f3f;
int h[N],f[M],ne[M],e[M],idx;
int n,m;
int S,T;
bool st[N];
int d[N];
int pre[N];

void add(int a,int b,int c)
{
    e[idx]=b,f[idx]=c,ne[idx]=h[a],h[a]=idx++;
}


bool bfs()
{
    memset(d,0,sizeof(d));
    memset(st,0,sizeof(st));
    memset(pre,0,sizeof(pre));
    d[S]=INF;
    st[S]=true;
    queue<int>q;
    q.push(S);
    while(q.size())
    {
        int t=q.front();
        q.pop();
        for(int i=h[t];~i;i=ne[i])
        {
            int j=e[i];
            if(f[i]>0&&!st[j])
            {  st[j]=true;
                d[j]=min(d[t],f[i]);
                pre[j]=i;
            if(j==T) return true;
                q.push(j);
          
            }
          
        }
    }
    return false;
}



void EK()
{
    int r=0;
    while(bfs())
    {
        r+=d[T];
        for(int i=T;i!=S;i=e[pre[i]^1])//存边
        {
            int id=pre[i];
            f[id]-=d[T],f[id^1]+=d[T];
        }
    }
    printf("%d\n",r);
}


int main()
{
    scanf("%d%d%d%d",&n,&m,&S,&T);
    memset(h,-1,sizeof(h));
    for(int i=1;i<=m;i++)
    {
        int a,b,c;
        scanf("%d%d%d",&a,&b,&c);
        add(a,b,c);
        add(b,a,0);
    }
    EK();
    return 0;
}

Dinic求最大流:

#include <bits/stdc++.h>
using namespace std;
const int N = 10010, M = 200010, INF = 1e8;
int n, m, S, T;
int h[N], e[M], f[M], ne[M], idx;
int q[N], d[N], cur[N];//q是队列,d是分成,cur是优化
void add(int a, int b, int c)
{
  e[idx] = b, f[idx] = c, ne[idx] = h[a], h[a] = idx ++;
  e[idx] = a, f[idx] = 0, ne[idx] = h[b], h[b] = idx ++;
}
int bfs()
{
  memset(d, -1, sizeof d);
  int tt = 0, hh = 0;
  q[0] = S, d[S] = 0, cur[S] = h[S];//当前弧是第一个点
  while (hh <= tt)
  {
    int t = q[hh ++ ];
    for (int i = h[t]; ~i; i = ne[i])
    {
      int ver = e[i];
      if (d[ver] == -1 && f[i])//当前点没有被搜索,且流量大于0
      {
        d[ver] = d[t] + 1;
        cur[ver] = h[ver];
        //当前点的当前弧 
        if (ver == T) return true;
        q[++ tt] = ver;
      }
    }
  }
  return false;
}
int find(int u, int limit )//从原点能够流向u这个点的最大流量为limit
{
  if (u == T) return limit;//如果已经到终点了 表示从原点到终点所能流的流量就是limit
  int flow = 0;//表示从u这个点开始往后流的流量是多少,dfs求,一开始是0的 
  //我们之前可能搜索u,可能有些路径满了,所以要将所有满的路径跳过
  for (int i = cur[u]; ~i && flow < limit; i = ne[i])//如果从u到终点的总流量等于limit就没有必要再搜了,因为起点到u最多就是limit 
  {
    cur[u] = i;//记录一下当前搜的弧是那个,流到第i条边,说明前面的边都流过了
    int ver = e[i];
    if (d[ver] == d[u] + 1 && f[i])//流到下一层,且当前弧可流
    {
      //从当前点开始最多可以有多少流量
      int t = find(ver, min(f[i], limit - flow));
      if (!t) //从这个点到终点没有流量,说明是不可用的,就把这个点删掉
        d[ver] = -1;//这个点到终点没有路径
      f[i] -= t, f[i ^ 1] += t, flow += t;
    }
  }
  return flow;
}
int dinic()
{
  int r = 0, flow;
  //判断如果有增广路并建立出分层图,然后找出所有增广路,将所有流量加起来
  while (bfs()) while (flow = find(S, INF)) r += flow;
  return r;
}
int main()
{
  cin >> n >> m >> S >> T;
  memset(h, -1, sizeof h);
  while (m -- )
  {
    int a, b, c; scanf("%d%d%d", &a, &b, &c);
    add(a, b, c);
  }
  printf("%d\n", dinic());
  return 0;
} 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值