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;
}
原文地址:https://www.cnblogs.com/sxprovence/p/5320043.html