Skip to content

Network flow 2

有流量下界的最大流

把每一条有下界的边分为必要边+不必要边。

  • Budget

最小费用最大流

每条边有一个单位流量所需的费用,求所有最大流中费用最小的。

  • Farm Tour

二部图最大匹配

左半部分无限边(1边也可以)连接对应的右半部分,超源点用1边连向所有左半部分,超汇点用1出边连接所有右半部分。调用最大流即可得到最大匹配数。

另一个解决二部图最大匹配问题的算法是匈牙利算法。

  • The perfect stall

    #include <iostream>
    #include <deque>
    #include <cstring>
    #include <algorithm>
    
    using namespace std;
    
    const int inf = 0x3f3f3f3f;
    const int maxv = 500;
    int V, E, s, t;
    
    int G[maxv][maxv]; // adjancency matrix
    int vis[maxv], dep[maxv];
    
    bool bfs() {
      int depth = 0;
      deque<int> q;
      memset(dep, -1, sizeof(dep));
      dep[s] = 0;
      q.push_back(s);
      while (!q.empty()) {
          int u = q.front(); q.pop_front();
          for (int i = 0; i < V; i++) {
              if (G[u][i] > 0 && dep[i] == -1) {
                  dep[i] = dep[u] + 1;
                  if (i == t) return true;
                  else q.push_back(i);
              }
          }
      }
      return false;
    }
    
    int dinic() {
      int mxflow = 0;
      deque<int> q;
      while (bfs()) {
          q.push_back(s);
          memset(vis, 0, sizeof(vis));
          vis[s] = 1;
          while (!q.empty()) {
              int u = q.back();
              // u is target
              if (u == t) {
                  int mnflow = inf;
                  int v; // mnflow_start_vertex
                  for (int i = 1; i < q.size(); i++) {
                      int vs = q[i - 1];
                      int ve = q[i];
                      if (G[vs][ve] > 0 && mnflow > G[vs][ve]) {
                          mnflow = G[vs][ve];
                          v = vs;
                      }
                  }
                  for (int i = 1; i < q.size(); i++) {
                      int vs = q[i - 1];
                      int ve = q[i];
                      G[vs][ve] -= mnflow;
                      G[ve][vs] += mnflow;
                  }
                  mxflow += mnflow;
                  // pop back 
                  while (!q.empty() && q.back() != v) {
                      vis[q.back()] = 0;
                      q.pop_back();
                  }
              }
              // u is not target
              else {
                  // only add one point in the next layer to stack.
                  bool found = false;
                  for (int i = 0; i < V; i++) {
                      if (G[u][i] > 0 && dep[i] == dep[u] + 1 && !vis[i]) {
                          vis[i] = 1;
                          q.push_back(i);
                          found = true;
                          break;
                      }
                  }
                  // can't find such point.
                  if (!found) q.pop_back();
              }
          }
      }
      return mxflow;
    }
    
    int N, M, a, b;
    
    int main() {
      while (cin >> N >> M) {
          V = N + M + 2;
          s = V - 2;
          t = V - 1;
          memset(G, 0, sizeof(G));
          for (int i = 0; i < N; i++) {
              cin >> a;
              for (int j = 0; j < a; j++) {
                  cin >> b;
                  G[i][N + b - 1] = inf;
              }
          }
          for (int i = 0; i < N; i++) G[s][i] = 1;
          for (int i = N; i < N + M; i++) G[i][t] = 1;
          cout << dinic() << endl;
      }
    }
    

最小割

最大流==最小割。

Figure 5 - A minimum cut in the network