• ZJOI 最小割 CQOI 不同的最小割 (最小割分治)


    题目1 ZJOI 最小割

    题目大意:

    求一个无向带权图两点间的最小割,询问小于等于c的点对有多少。

    算法讨论: 最小割 分治

    代码:

    #include <cstdlib>
    #include <iostream>
    #include <cstring>
    #include <algorithm>
    #include <cstdio>
    #include <vector>
     
    using namespace std;
    const int N = 150 + 5;
    const int M = 3000 + 5;
    const int oo = 0x3f3f3f3f;
    #define inf oo
     
    int n, m;
    bool mark[N];
    int a[N], tmp[N], ans[N][N];
     
    struct Edge {
      int from, to, cap, flow;
      Edge(int u = 0, int v = 0, int c = 0, int f = 0) :
        from(u), to(v), cap(c), flow(f) {}
    };
     
    struct Dinic {
      int n, mm, s, t;
      int dis[N], cur[N], que[N * 10];
      bool vis[N];
      vector <Edge> edges;
      vector <int> G[N];
     
      void clear() {
        for(int i = 0; i <= n; ++ i) G[i].clear();
        edges.clear();
      }
     
      void add(int from, int to, int cap) {
        edges.push_back(Edge(from, to, cap, 0));
        edges.push_back(Edge(to, from, cap, 0));
        mm = edges.size();
        G[from].push_back(mm - 2);
        G[to].push_back(mm - 1);
      }
     
      bool bfs() {
        int head = 1, tail = 1;
        memset(vis, false, (n + 1) * sizeof (bool));
        dis[s] = 0; vis[s] = true; que[head] = s;
        while(head <= tail) {
          int x = que[head];
          for(int i = 0; i < (signed) G[x].size(); ++ i) {
            Edge &e = edges[G[x][i]];
            if(!vis[e.to] && e.cap > e.flow) {
              vis[e.to] = true;
              dis[e.to] = dis[x] + 1;
              que[++ tail] = e.to;
            }
          }
          ++ head;
        }
        return vis[t];
      }
     
      int dfs(int x, int a) {
        if(x == t || a == 0) return a;
        int flw = 0, f;
        for(int &i = cur[x]; i < (signed) G[x].size(); ++ i) {
          Edge &e = edges[G[x][i]];
          if(dis[e.to] == dis[x] + 1 && (f = dfs(e.to, min(a, e.cap - e.flow))) > 0) {
            e.flow += f; edges[G[x][i] ^ 1].flow -= f; flw += f; a -= f;
            if(a == 0) break;
          }
        }
        return flw;
      }
     
      int maxflow(int s, int t) {
        this->s = s; this->t = t;
        int flw = 0;
        while(bfs()) {
          memset(cur, 0, sizeof cur);
          flw += dfs(s, oo);
        }
        return flw;
      }
     
      void rebuild() {
        for(int i = 0; i < (signed) edges.size(); ++ i)
          edges[i].flow = 0;
      }
     
      void dfs(int u) {
        mark[u] = true;
        for(int i = 0; i < (signed) G[u].size(); ++ i) {
          Edge e = edges[G[u][i]];
          if(!mark[e.to] && e.cap > e.flow) {
            dfs(e.to);
          } 
        }
      }
    }net;
     
    void Divide(int l, int r) {
      if(l >= r) return;
      net.rebuild();
      int nowflow = net.maxflow(a[l], a[r]);
      memset(mark, false, (n + 1) * sizeof (bool));
      net.dfs(a[l]);
      for(int i = 1; i <= n; ++ i)
        if(mark[i])
          for(int j = 1; j <= n; ++ j)
            if(!mark[j])
              ans[i][j] = min(ans[i][j], nowflow), ans[j][i] = ans[i][j];
      int L = l, R = r;
      for(int i = l; i <= r; ++ i)
        if(mark[a[i]]) tmp[L ++] = a[i];
        else tmp[R --] = a[i];
      for(int i = l; i <= r; ++ i) a[i] = tmp[i];
      Divide(l, L - 1); Divide(R + 1, r);//这不能二分一个Mid,因为S集和T集的大小不一定相同
    }
     
    int main() {
      int T, u, v, c, q;
      scanf("%d", &T);
      while(T --) {
        net.clear(); 
        scanf("%d%d", &n, &m); net.n = n;
        for(int i = 1; i <= n; ++ i) a[i] = i;
        for(int i = 1; i <= n; ++ i)
          for(int j = 1; j <= n; ++ j) ans[i][j] = inf;
        for(int i = 1; i <= m; ++ i) {
          scanf("%d%d%d", &u, &v, &c);
          net.add(u, v, c);
        }
        Divide(1, n);
        scanf("%d", &q);
        for(int i = 1; i <= q; ++ i) {
          int tmp = 0;
          scanf("%d", &c);
          for(int u = 1; u <= n; ++ u) {
            for(int v = u + 1; v <= n; ++ v) {
              if(ans[u][v] <= c) {
                ++ tmp;
              }
            }
          }
          printf("%d
    ", tmp);
        }
        puts("");
      }
      return 0;
    }
    

    题目2 CQOI2016 不同的最小割

    题目大意:

    求所有点对问不同的最小割数目。

    算法讨论: 最小割 分治

    和上面的一个题有区别么?

    代码:

    #include <cstdlib>
    #include <iostream>
    #include <cstring>
    #include <algorithm>
    #include <cstdio>
    #include <vector>
    #include <set>
     
    using namespace std;
    const int N = 850 + 5;
    const int M = 8500 + 5;
    const int oo = 0x3f3f3f3f;
     
    int n, m;
    int ans[N][N], tmp[N], a[N];
    bool mark[N];
    set <int> lts;
     
    struct Edge {
      int from, to, cap, flow;
      Edge(int u = 0, int v = 0, int cap = 0, int flow = 0):
        from(u), to(v), cap(cap), flow(flow) {}
    };
     
    struct Dinic {
      int n, m, s, t;
      int dis[N], cur[N], que[N * 10];
      bool vis[N];
      vector <Edge> edges;
      vector <int> G[N];
     
      void add(int from, int to, int cap) {
        edges.push_back(Edge(from, to, cap, 0));
        edges.push_back(Edge(to, from, cap, 0));
        m = edges.size();
        G[from].push_back(m - 2);
        G[to].push_back(m - 1);
      }
     
      bool bfs() {
        int head = 1, tail = 1;
        memset(vis, false, (n + 1) * sizeof (bool));
        dis[s] = 0; vis[s] = true; que[head] = s;
        while(head <= tail) {
          int x = que[head];
          for(int i = 0; i < (signed) G[x].size(); ++ i) {
            Edge &e = edges[G[x][i]];
            if(!vis[e.to] && e.cap > e.flow) {
              vis[e.to] = true;
              dis[e.to] = dis[x] + 1;
              que[++ tail] = e.to;
            }
          }
          ++ head;
        }
        return vis[t];
      }
     
      int dfs(int x, int a) {
        if(x == t || a == 0) return a;
        int flw = 0, f;
        for(int &i = cur[x]; i < (signed) G[x].size(); ++ i) {
          Edge &e = edges[G[x][i]];
          if(dis[e.to] == dis[x] + 1 && (f = dfs(e.to, min(a, e.cap - e.flow))) > 0) {
            e.flow += f; edges[G[x][i] ^ 1].flow -= f; a -= f; flw += f;
            if(a == 0) break;
          }
        }
        return flw;
      }
     
      int maxflow(int s, int t) {
        this->s = s; this->t = t;
        int flw = 0;
        while(bfs()) {
          memset(cur, 0, sizeof cur);
          flw += dfs(s, oo);
        }
        return flw;
      }
     
      void rebuild() {
        for(int i = 0; i < (signed) edges.size(); ++ i)
          edges[i].flow = 0;
      }
     
      void dfs(int u) {
        mark[u] = true;
        for(int i = 0; i < (signed) G[u].size(); ++ i) {
          Edge e = edges[G[u][i]];
          if(!mark[e.to] && e.cap > e.flow)
            dfs(e.to);
        }
      }
    }net;
     
    void Divide(int l, int r) {
      if(l >= r) return;
      net.rebuild();
      int nowflow = net.maxflow(a[l], a[r]);
      memset(mark, false, (n + 1) * sizeof(bool));
      net.dfs(a[l]);
      for(int i = 1; i <= n; ++ i)
        if(mark[i])
          for(int j = 1; j <= n; ++ j)
            if(!mark[j])
              ans[i][j] = min(ans[i][j], nowflow), ans[j][i] = ans[i][j];
      int L = l, R = r;
      for(int i = l; i <= r; ++ i)
        if(mark[a[i]]) tmp[L ++] = a[i];
        else tmp[R --] = a[i];
      for(int i = l; i <= r; ++ i)
        a[i] = tmp[i];
      Divide(l, L - 1); Divide(R + 1, r);
    }
     
    int main() {
      int u, v, c;
      scanf("%d%d", &n, &m);
      for(int i = 1; i <= m; ++ i) {
        scanf("%d%d%d", &u, &v, &c);
        net.add(u, v, c);
      }
      for(int i = 1; i <= n; ++ i) a[i] = i;
      for(int i = 1; i <= n; ++ i)
        for(int j = 1; j <= n; ++ j) ans[i][j] = oo;
      net.n = n;
      Divide(1, n);
      for(int i = 1; i <= n; ++ i) {
        for(int j = i + 1; j <= n; ++ j) {
          lts.insert(ans[i][j]);
        }
      }
      printf("%d
    ", lts.size());
      return 0;
    }
    
  • 相关阅读:
    896. Monotonic Array单调数组
    865. Smallest Subtree with all the Deepest Nodes 有最深节点的最小子树
    489. Robot Room Cleaner扫地机器人
    JavaFX
    《Python CookBook2》 第一章 文本
    《Python CookBook2》 第一章 文本
    《Python CookBook2》 第一章 文本
    《Python CookBook2》 第一章 文本
    《Python CookBook2》 第一章 文本
    《Python CookBook2》 第一章 文本
  • 原文地址:https://www.cnblogs.com/sxprovence/p/5320043.html
Copyright © 2020-2023  润新知