zoukankan      html  css  js  c++  java
  • 【Luogu P2764】最小路径覆盖问题

    网络流 (24) 题之一。

    Problem

    Description

    给出一个 (n) 个点 (m) 条边的 (DAG) ,求最小路径点覆盖,并输出路径选择方案。

    Input Format

    第一行有 (2) 个正整数 (n)(m)(n) 是给定( ext{GAP})(有向无环图) (G) 的顶点数, (m)(G) 的边数。接下来的 (m) 行,每行有两个正整数 (i)(j) 表示一条有向边 ((i,j))

    Output Format

    从第1 行开始,每行输出一条路径。文件的最后一行是最少路径数。

    Sample

    Input

    11 12
    1 2
    1 3
    1 4
    2 5
    3 6
    4 7
    5 8
    6 9
    7 10
    8 11
    9 11
    10 11
    

    Output

    1 4 7 10 11
    2 5 8
    3 6 9
    3
    

    Range

    (1leq nleq 150,1leq mleq 6000)

    Mentality

    这题其实就是 (DAG) 上的最小路径点覆盖,详情参考这篇 (blog)

    其实这里只要叙述怎么处理方案的输出就好了 ......

    我们对于二分图跑完最大流之后,扫一遍二分图中所有的边 (并不包括连向超级源点汇点的边) ,根据网络流残余网络的特性,如果某一条边的反边中剩余容量不为 (0) ,那么它必定是最大流中的一条可行弧。则我们记录下这条边,对于左侧点 (i) ,记录一个 (next[i]) 代表 (i) 连向的边,并记录右侧点 (j') 是否被经过。接着,我们扫一遍右边的点,如果 (i') 没有被任何一条边经过,则入度为 (0) ,必定为路径起点,那么我们从 (i) 开始借助 (next) 数组遍历这条路径并输出即可。

    Code

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <queue>
    using namespace std;
    int n, m, S, T;
    int head[1001], nx[20001], to[20001], w[20001], cnt;
    int deep[1001], nt[1001];
    bool book[20001], r[1001];
    int inf = 1e9, ans;
    void add(int u, int v, int W, int d) {
      to[d] = v, nx[d] = head[u], w[d] = W;
      head[u] = d;
    }
    queue<int> q;
    bool init() {
      memset(book, 0, sizeof(book));
      memset(deep, -1, sizeof(deep));
      deep[S] = 1;
      q.push(S);
      while (!q.empty()) {
        int x = q.front();
        q.pop();
        for (int i = head[x]; i; i = nx[i])
          if (deep[to[i]] == -1 && w[i] > 0) {
            deep[to[i]] = deep[x] + 1;
            q.push(to[i]);
          }
      }
      return deep[T] != -1;
    }
    int dfs(int x, int limit) {
      if (x == T || !limit) return limit;
      int flow = 0, fnow;
      for (int i = head[x]; i; i = nx[i])
        if (deep[to[i]] == deep[x] + 1 && !book[i] &&
            (fnow = dfs(to[i], min(limit, w[i])))) {
          book[i] = true;
          flow += fnow;
          limit -= fnow;
          w[i] -= fnow;
          w[i ^ 1] += fnow;
          if (!limit) break;
        }
      return flow;
    }
    void print(int x) {
      if (!x) return;
      printf("%d ", x);
      print(nt[x]);
    }
    int main() {
      cin >> n >> m;
      S = n * 2 + 1, T = n * 2 + 2, cnt = 1;
      for (int i = 1; i <= n; i++) {
        add(S, i, 1, ++cnt);
        add(i, S, 0, ++cnt);
        add(i + n, T, 1, ++cnt);
        add(T, i + n, 0, ++cnt);
      }
      int u, v;
      for (int i = 1; i <= m; i++) {
        scanf("%d%d", &u, &v);
        v += n;
        add(u, v, inf, ++cnt);
        add(v, u, 0, ++cnt);
      }
      while (init()) dfs(S, inf);
      for (int i = 2; i <= cnt; i += 2) {
        int p1 = to[i], p2 = to[i ^ 1];
        if (p1 == S || p1 == T || p2 == S || p2 == T) continue;
        if (w[i ^ 1]) nt[to[i ^ 1]] = to[i] - n, r[to[i] - n] = true;
      }
      for (int i = 1; i <= n; i++)
        if (!r[i]) {
          ans++;
          print(i);
          cout << endl;
        }
      cout << ans;
    }
    
    
  • 相关阅读:
    [LC] 252. Meeting Rooms
    [LC] 243. Shortest Word Distance
    [LC] 215. Kth Largest Element in an Array
    [LC] 8. String to Integer (atoi)
    [LC] 367. Valid Perfect Square
    [LC] 66. Plus One
    [LC] 7. Reverse Integer
    [GeeksForGeeks] Print all nodes that don't have sibling in a binary tree.
    [Coding Made Simple] Maximum Sum Subsequence Non-adjacent
    [Coding Made Simple] Longest Bitonic Subsequence
  • 原文地址:https://www.cnblogs.com/luoshuitianyi/p/10333974.html
Copyright © 2011-2022 走看看