[BZOJ 2561]最小生成树

danihao123 posted @ 2018年3月15日 16:01 in 题解 with tags BZOJ 最小割 , 704 阅读
转载请注明出处:http://danihao123.is-programmer.com/

窝只会做水体了qwq

因为这条边既存在在最大生成树里,又存在在最小生成树里。那就说明\(u\)到\(v\)的路径上,在最大生成树上这条边是最小的,在最小生成树上这条边是最大的。

所以说我们不能用大于\(L\)的边来联通\(u\)和\(v\),也不能用小于\(L\)的边,于是乎……跑两次最小割即可。

代码:

/**************************************************************
	Problem: 2561
	User: danihao123
	Language: C++
	Result: Accepted
	Time:1528 ms
	Memory:15952 kb
****************************************************************/

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cctype>
#include <utility>
#include <algorithm>
#include <queue>
const int maxn = 20005;
const int maxm = 200005;
const int maxe = maxm << 2;
int n, m;
int first[maxn];
int next[maxe], to[maxe], flow[maxe], cap[maxe];
int gcnt = 0;
inline void init_graph() {
  gcnt = 0;
  std::fill(first + 1, first + 1 + n, 0);
}
inline void add_edge(int u, int v, int f) {
  gcnt ++;
  next[gcnt] = first[u];
  first[u] = gcnt;
  to[gcnt] = v;
  flow[gcnt] = 0; cap[gcnt] = f;
}
inline int rev(int i) {
  return (((i - 1) ^ 1) + 1);
}
inline void ins_edge(int u, int v, int f) {
  add_edge(u, v, f);
  add_edge(v, u, 0);
}

int line[maxm][3];
int d[maxn];
int s, t;
inline bool bfs() {
  static bool vis[maxn];
  std::fill(vis + 1, vis + 1 + n, false);
  std::fill(d + 1, d + 1 + n, 0);
  std::queue<int> Q;
  Q.push(s); vis[s] = true; d[s] = 1;
  while(!Q.empty()) {
    int u = Q.front(); Q.pop();
    for(int i = first[u]; i; i = next[i]) {
      int v = to[i];
      if(!vis[v] && cap[i] > flow[i]) {
        d[v] = d[u] + 1; vis[v] = true;
        Q.push(v);
      }
    }
  }
  return vis[t];
}
int cur[maxn];
int dfs(int x, int a) {
  if(a == 0 || x == t) return a;
  int ans = 0;
  for(int &i = cur[x]; i; i = next[i]) {
    int v = to[i];
    int f;
    if(d[v] == d[x] + 1 && (f = dfs(v, std::min(a, cap[i] - flow[i]))) > 0) {
      ans += f; a -= f;
      flow[i] += f; flow[rev(i)] -= f;
      if(a == 0) break;
    }
  }
  if(a > 0) d[x] = -1;
  return ans;
}
int dinic() {
  int ans = 0;
  while(bfs()) {
    for(int i = 1; i <= n; i ++) cur[i] = first[i];
    ans += dfs(s, 0x7fffffff);
  }
  return ans;
}

int main() {
  scanf("%d%d", &n, &m);
  for(int i = 1; i <= m; i ++) {
    int *l = line[i];
    scanf("%d%d%d", &l[0], &l[1], &l[2]);
  }
  int L; scanf("%d%d%d", &s, &t, &L);
  for(int i = 1; i <= m; i ++) {
    int *l = line[i];
    if(l[2] < L) {
      ins_edge(l[0], l[1], 1);
      ins_edge(l[1], l[0], 1);
    }
  }
  int ans = dinic();
  init_graph();
  for(int i = 1; i <= m; i ++) {
    int *l = line[i];
    if(l[2] > L) {
      ins_edge(l[0], l[1], 1);
      ins_edge(l[1], l[0], 1);
    }
  }
  ans += dinic();
  printf("%d\n", ans);
  return 0;
}

登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter