最大流Dinic算法

摘自大神博客:

http://www.cnblogs.com/SYCstudio/p/7260613.html


增广路定理+分层图+当前弧优化

增广路:从源点出发不停的通过dfs出一条路径到汇点(直到无法走到汇点),每次dfs找出路径中最小残量,回溯时都减掉这个最小残量,并且连一条回边(原因如下图 :)


分层图:发现增广图处理下图问题非常耗时(s->v->u->t而不是s->v->t),所以每次dfs前都先用bfs求一次深度dep,且dfs时只允许低深度到高深度


当前弧优化:每次dfs不是从汇点的第一条边开始,而是用cur数组记录u循环到哪条边,以此来加速

上代码:

int n, m, s, t;
struct edge
{
  int to, w, nx;
} e[N << 1];
int fi[N];
int ce = 1;
int dep[N];
bool vis[N];
int cur[N];
inline void add(int u, int v, int w)
{
  e[++ce] = edge{v, w, fi[u]};
  fi[u] = ce;
}
int bfs()
{
  me(dep, 0);
  queue<int> q;
  q.push(s);
  dep[s] = 1;//特别注意这里赋值个不为0的数,不然就是死循环!!!
  while (!q.empty())
  {
    int u = q.front();
    q.pop();
    for (int i = fi[u]; ~i; i = e[i].nx)
    {
      int v = e[i].to;

      if (e[i].w && !dep[v])
      {
        dep[v] = dep[u] + 1;
        q.push(v);
      }
    }
  }
  return dep[t];
}
int dfs(int u, int flow)
{
  if (u == t)
    return flow;
  for (int &i = cur[u]; ~i; i = e[i].nx)
  {
    int v = e[i].to;
    if (e[i].w && dep[u] + 1 == dep[v])
    {
      int di = dfs(v, min(e[i].w, flow));
      if (di)
      {
        e[i].w -= di, e[i ^ 1].w += di;
        return di;
      }
    }
  }
  return 0;
}
int dinic(int s, int t)
{
  int res = 0;
  int cnt = 0;
  while (bfs())
  {
    if (++cnt > 20)
      break;
    For(i, 1, n) cur[i] = fi[i];
    while (int di = dfs(s, inf))
      res += di;
  }
  return res;
}
int main()
{
#ifndef ONLINE_JUDGE
  file("test");
#endif
  me(fi, -1);
  sdf(n), sdf(m), sdf(s), sdf(t);
  while (m--)
  {
    int u, v, w;
    sdf(u), sdf(v), sdf(w);
    add(u, v, w), add(v, u, 0);
  }
  printf("%d", dinic(s, t));
  return 0;
}
posted @ 2018-08-02 19:59  planche  阅读(122)  评论(0编辑  收藏  举报