[Flows] 网络流做题记录

Some Templates

Maximum Flow (Minimum Cut)

template < class T, int N, int M >
struct MaxFlow {
  int n;
  int cnt = 1, head[N];
  struct Edge {
    T flow;
    int nxt, node;
  } e[M << 1];
  int dep[N], cur[N], flow_sink;
  void add_edge_ (int u, int v, T flow) {
    cnt ++;
    e[cnt].nxt = head[u];
    e[cnt].node = v;
    e[cnt].flow = flow;
    head[u] = cnt;
    return ;
  }
  void add_edge (int u, int v, T flow) {
    add_edge_ (u, v, flow);
    add_edge_ (v, u, 0);
    return ;
  }
  T dfs (int u, T remain) {
    if (u == flow_sink) {
      return remain;
    }
    T res = 0;
    for (int i = cur[u]; i && remain; i = e[i].nxt) {
      cur[u] = i;
      T f = std :: min (remain, e[i].flow);
      int v = e[i].node;
      if (dep[u] + 1 == dep[v] && f) {
        T f_ = dfs (v, f);
        res += f_;
        remain -= f_;
        e[i].flow -= f_;
        e[i ^ 1].flow += f_;
      }
    }
    if (!res) {
      dep[u] = -1;
    }
    return res;
  }
  T Flow (int source, int sink) {
    flow_sink = sink;
    T res = 0;
    while (true) {
      std :: queue < int > q;
      while (!q.empty ()) {
        q.pop ();
      }
      for (int i = 0;i <= n; ++ i) {
        cur[i] = head[i];
        dep[i] = -1;
      }
      q.push (source);
      dep[source] = 0;
      while (!q.empty ()) {
        int u = q.front ();
        q.pop ();
        for (int i = head[u]; i ; i = e[i].nxt) {
          if (dep[e[i].node] == -1 && e[i].flow) {
            dep[e[i].node] = dep[u] + 1;
            q.push (e[i].node);
          }
        }
      }
      if (dep[sink] == -1) {
        return res;
      }
      res += dfs (source, 1e18);
    }
    return 0;
  }
  void init (int n_) {
    n = n_;
    cnt = 1;
    for (int i = 1;i <= n; ++ i) {
      head[i] = 0;
    }
    return ;
  }
};

Minimum Cost Maximum Flow

template < class T, int N, int M, i64 INF >
struct MinCost_MaxFlow {
  struct Edge {
    int node, nxt;
    T flow, cost;
  } e[M << 1];
  struct Node {
    int node, id;
  } p[M];
  int n;
  int cnt = 1, head[N];
  int vis[N], flow_source, flow_sink;
  T MaxFlow, MinCost, dis[N], h[N];
  void add_edge_ (int u, int v, T flow, T cost) {
    cnt ++;
    e[cnt].node = v;
    e[cnt].flow = flow;
    e[cnt].cost = cost;
    e[cnt].nxt = head[u];
    head[u] = cnt;
    return ;
  }
  bool dijkstra () {
    std :: priority_queue < std :: pair < T, int >, 
    std :: vector < std :: pair < T, int > >, 
    std :: greater < std :: pair < T, int > > > q;
    while (!q.empty ()) {
      q.pop ();
    }
    for (int i = 1;i <= n; ++ i) {
      dis[i] = (T) (INF);
      vis[i] = 0;
    }
    dis[flow_source] = 0;
    q.push (std :: make_pair (0, flow_source));
    while (!q.empty ()) {
      int u = q.top ().second;
      q.pop ();
      if (vis[u]) {
        continue;
      }
      vis[u] = 1;
      for (int i = head[u]; i; i = e[i].nxt) {
        int v = e[i].node;
        T w = e[i].cost + h[u] - h[v];
        if (e[i].flow != 0 && dis[v] > dis[u] + w) {
          dis[v] = dis[u] + w;
          p[v].node = u;
          p[v].id = i;
          if (!vis[v]) {
            q.push (std :: make_pair (dis[v], v));
          }
        }
      }
    }
    if (dis[flow_sink] != (T) (INF)) return true;
    else return false;
  }
  void SPFA () {
    std :: queue < int > q;
    while (!q.empty ()) {
      q.pop ();
    }
    std :: memset (h, 63, sizeof h);
    h[flow_source] = 0;
    vis[flow_source] = 1;
    q.push (flow_source);
    while (!q.empty ()) {
      int u = q.front ();
      q.pop ();
      vis[u] = 0;
      for (int i = head[u]; i; i = e[i].nxt) {
        int v = e[i].node;
        if (e[i].flow != 0 && h[v] > h[u] + e[i].cost) {
          h[v] = h[u] + e[i].cost;
          if (!vis[v]) {
            vis[v] = 1;
            q.push (v);
          }
        }
      }
    }
    return ;
  }
  void add_edge (int u, int v, T flow, T cost) {
    add_edge_ (u, v, flow, cost);
    add_edge_ (v, u, 0, -cost);
    return ;
  }
  std :: pair < T, T > Flow (int source, int sink) {
    flow_source = source;
    flow_sink = sink;
    SPFA ();
    MaxFlow = 0;
    MinCost = 0;
    while (dijkstra ()) {
      T w = INF;
      for (int i = 1;i <= n; ++ i) {
        h[i] += dis[i];
      }
      for (int i = sink; i != source; i = p[i].node) {
        w = std :: min (w, e[p[i].id].flow);
      }
      for (int i = sink; i != source; i = p[i].node) {
        e[p[i].id].flow -= w;
        e[p[i].id ^ 1].flow += w;
      }
      MaxFlow += w;
      MinCost += w * h[sink];
    }
    return std :: make_pair (MaxFlow, MinCost);
  }
  void init (int n_) {
    n = n_;
    cnt = 1;
    MaxFlow = 0;
    MinCost = 0;
    for (int i = 1;i <= n; ++ i) {
      head[i] = h[i] = vis[i] = dis[i] = 0;
    }
    flow_source = 0;
    flow_sink = 0;
    return ;
  }
};

洛谷 P2045 方格取数加强版

考虑拆点,将 \((i, j)\) 这个点拆成入点和出点,下面写为 \(in(i, j)\)\(out(i, j)\)

考虑用 表示这个点的 经过次数,用 费用 表示 所经过的数的和

  • 第一次经过 \((i, j)\),获利 \(a_i\),从 \(in(i, j)\)\(out(i, j)\) 连一条 容量为 \(\symbfit{1}\),费用为 \(\symbfit{a_{i, j}}\) 的边。

  • 以前已经经过过 \((i, j)\),获利 \(0\),从 \(in(i, j)\)\(out(i, j)\) 连一条 容量为 \(\symbfit{+\infty}\),费用为 \(\symbfit{0}\) 的边。

  • \((i, j)\) 向右走到 \((i, j + 1)\),获利 \(0\),从 \(out(i, j)\)\(in(i, j + 1)\) 连一条 容量为 \(\symbfit{+\infty}\),费用为 \(\symbfit{0}\) 的边。

  • \((i, j)\) 向下走到 \((i + 1, j)\),获利 \(0\),从 \(out(i, j)\)\(in(i + 1, j)\) 连一条 容量为 \(\symbfit{+\infty}\),费用为 \(\symbfit{0}\) 的边。

最终的 源点设为 \(\symbfit{S}\),并向 \(\symbfit{in(1, 1)}\) 连容量为 \(\symbfit{k}\),费用为 \(\symbfit{0}\) 的边。汇点即为 \(\symbfit{out(n, n)}\)

最后跑一遍最费用最大流即可,可以将费用取反跑最费用最大流。

Code
#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#include <ext/pb_ds/hash_policy.hpp>
#include <ext/rope>
bool Mbe;
typedef long long i64;
typedef unsigned long long u64;
typedef __int128 i128;
std :: mt19937 rnd (std :: time (0));
template < class T > T gen (const T l, const T r) {return rnd () % (r - l + 1) + l;}
const double pi = std :: acos (-1);
template < class T > inline void read (T &val) {
  T x = 0;
  bool f = false;
  char c = std :: getchar ();
  for ( ; c < '0' || c > '9' ; c = std :: getchar ()) f |= (c == '-');
  for ( ; c >= '0' && c <= '9' ; c = std :: getchar ()) x = (x << 1) + (x << 3) + (c & 15);
  val = (!f) ? (x) : (-x);
  return ;
}
#define debug(fmt, ...) fprintf(stderr, fmt, ##__VA_ARGS__)
const i64 hashmod1 = 2147483579, hashmod2 = 1610612741, hashmod3 = 805306457;
template < class T, class I > void chkmin (T &p, I q) {T q_ = q; p = std :: min (p, q_); return ;}
template < class T, class I > void chkmax (T &p, I q) {T q_ = q; p = std :: max (p, q_); return ;}
template < class T, int N, int M, i64 INF >
struct MinCost_MaxFlow {
  struct Edge {
    int node, nxt;
    T flow, cost;
  } e[M << 1];
  struct Node {
    int node, id;
  } p[M];
  int n;
  int cnt = 1, head[N];
  int vis[N], flow_source, flow_sink;
  T MaxFlow, MinCost, dis[N], h[N];
  void add_edge_ (int u, int v, T flow, T cost) {
    cnt ++;
    e[cnt].node = v;
    e[cnt].flow = flow;
    e[cnt].cost = cost;
    e[cnt].nxt = head[u];
    head[u] = cnt;
    return ;
  }
  bool dijkstra () {
    std :: priority_queue < std :: pair < T, int >, 
    std :: vector < std :: pair < T, int > >, 
    std :: greater < std :: pair < T, int > > > q;
    while (!q.empty ()) {
      q.pop ();
    }
    for (int i = 1;i <= n; ++ i) {
      dis[i] = (T) (INF);
      vis[i] = 0;
    }
    dis[flow_source] = 0;
    q.push (std :: make_pair (0, flow_source));
    while (!q.empty ()) {
      int u = q.top ().second;
      q.pop ();
      if (vis[u]) {
        continue;
      }
      vis[u] = 1;
      for (int i = head[u]; i; i = e[i].nxt) {
        int v = e[i].node;
        T w = e[i].cost + h[u] - h[v];
        if (e[i].flow != 0 && dis[v] > dis[u] + w) {
          dis[v] = dis[u] + w;
          p[v].node = u;
          p[v].id = i;
          if (!vis[v]) {
            q.push (std :: make_pair (dis[v], v));
          }
        }
      }
    }
    if (dis[flow_sink] != (T) (INF)) return true;
    else return false;
  }
  void SPFA () {
    std :: queue < int > q;
    while (!q.empty ()) {
      q.pop ();
    }
    std :: memset (h, 63, sizeof h);
    h[flow_source] = 0;
    vis[flow_source] = 1;
    q.push (flow_source);
    while (!q.empty ()) {
      int u = q.front ();
      q.pop ();
      vis[u] = 0;
      for (int i = head[u]; i; i = e[i].nxt) {
        int v = e[i].node;
        if (e[i].flow != 0 && h[v] > h[u] + e[i].cost) {
          h[v] = h[u] + e[i].cost;
          if (!vis[v]) {
            vis[v] = 1;
            q.push (v);
          }
        }
      }
    }
    return ;
  }
  void add_edge (int u, int v, T flow, T cost) {
    add_edge_ (u, v, flow, cost);
    add_edge_ (v, u, 0, -cost);
    return ;
  }
  std :: pair < T, T > Flow (int source, int sink) {
    flow_source = source;
    flow_sink = sink;
    SPFA ();
    MaxFlow = 0;
    MinCost = 0;
    while (dijkstra ()) {
      T w = INF;
      for (int i = 1;i <= n; ++ i) {
        h[i] += dis[i];
      }
      for (int i = sink; i != source; i = p[i].node) {
        w = std :: min (w, e[p[i].id].flow);
      }
      for (int i = sink; i != source; i = p[i].node) {
        e[p[i].id].flow -= w;
        e[p[i].id ^ 1].flow += w;
      }
      MaxFlow += w;
      MinCost += w * h[sink];
    }
    return std :: make_pair (MaxFlow, MinCost);
  }
  void init (int n_) {
    n = n_;
    cnt = 1;
    MaxFlow = 0;
    MinCost = 0;
    for (int i = 1;i <= n; ++ i) {
      head[i] = h[i] = vis[i] = dis[i] = 0;
    }
    flow_source = 0;
    flow_sink = 0;
    return ;
  }
};
int n, k;
i64 a[65][65];
MinCost_MaxFlow < i64, 5027, 10026, (i64) (1e18) > g;
bool Med;
signed main () {
  debug ("%.8lf MB\n", (&Mbe - &Med) / 1048576.0);
  read (n), read (k);
  for (int i = 1;i <= n; ++ i) {
    for (int j = 1;j <= n; ++ j) {
      read (a[i][j]);
    }
  }
  g.init (2 * n * n + 1);
  #define id_IN(x, y) (x - 1) * n + y + 1
  #define id_OUT(x, y) n * n + (x - 1) * n + y + 1
  for (int i = 1;i <= n; ++ i) {
    for (int j = 1;j <= n; ++ j) {
      g.add_edge (id_IN (i, j), id_OUT (i, j), 1, -a[i][j]);
      g.add_edge (id_IN (i, j), id_OUT (i, j), 1e18, 0);
      if (i != n) g.add_edge (id_OUT (i, j), id_IN (i + 1, j), 1e18, 0);
      if (j != n) g.add_edge (id_OUT (i, j), id_IN (i, j + 1), 1e18, 0);
    }
  }
  g.add_edge (1, id_IN (1, 1), k, 0);
  auto ans = g.Flow (1, id_OUT (n, n));
  printf ("%lld\n", -ans.second);
  #undef id_IN
  #undef id_OUT
  debug ("%.8lf ms\n", 1e3 * clock () / CLOCKS_PER_SEC);
  return 0;
}
// g++ "a.cpp" -o a -std=c++14 -O2 -Wall -Wextra -Wshadow
// check! no inline! (except fastIO)
posted @ 2024-02-16 19:59  CountingGroup  阅读(7)  评论(0编辑  收藏  举报