Codeforces Round #188 (Div. 1) C. Balance


首先,一个联通块里的 $a$ 之和与 $b$ 之和必须相等才有可能,然后就暴力枚举两个点,将 $a>b$ 的找一条路引向 $a<b$ 的,本来以为可以类似于拓扑排序的,就找叶子节点,但发现没办法,因为有可能没法满足最大流量要小于一个值的要求。

#include <bits/stdc++.h>

const int N = 305;
const int ME = 2 * 5e4 + 7;
const int M = 2 * N * N;

struct E {
  int v, ne;
} e[ME];
int head[N], cnt = 1, n, v, m;

void add(int u, int v) {
  e[++cnt].v = v; e[cnt].ne = head[u]; head[u] = cnt;
}

int color[N], colorNum;
long long sa[N], sb[N];
int a[N], b[N];

void dfs(int u, int colorIndex) {
  color[u] = colorIndex;
  sa[colorIndex] += a[u];
  sb[colorIndex] += b[u];
  for (int i = head[u]; i; i = e[i].ne) {
    int v = e[i].v;
    if (!color[v])
      dfs(v, colorIndex);
  }
}

bool col() {
  for (int i = 1; i <= n; i++)
    if (!color[i]) dfs(i, ++colorNum);
  for (int i = 1; i <= colorNum; i++)
    if (sa[i] != sb[i]) return 0;
  return 1;
}

int res, ans[M][3], pre[N];
bool vis[N];

void findpath(int st, int ed) {
  std::queue<int> que;
  pre[st] = 0;
  que.push(st);
  memset(vis, 0, sizeof(vis));
  while (!que.empty()) {
    int u = que.front(); que.pop();
    vis[u] = 1;
    if (u == ed) return;
    for (int i = head[u]; i; i = e[i].ne) {
      int v = e[i].v;
      if (vis[v]) continue;
      pre[v] = u;
      que.push(v);
    }
  }
}

void solve(int st, int ed, int need) {
  if (st == ed) return;
  int can = std::min(a[pre[ed]], need);
  ans[res][0] = pre[ed], ans[res][1] = ed, ans[res][2] = can;
  if (can) {
    res++;
    a[pre[ed]] -= can;
    a[ed] += can;
  }
  solve(st, pre[ed], need);
  if (can < need) {
    can = need - can;
    ans[res][0] = pre[ed], ans[res][1] = ed, ans[res][2] = can;
    res++;
    a[pre[ed]] -= can;
    a[ed] += can;
  }
}

int main() {
  scanf("%d%d%d", &n, &v, &m);
  for (int i = 1; i <= n; i++)
    scanf("%d", a + i);
  for (int i = 1; i <= n; i++)
    scanf("%d", b + i);
  for (int i = 1, x, y; i <= m; i++) {
    scanf("%d%d", &x, &y);
    add(x, y); add(y, x);
  }
  if (!col()) {
    puts("NO");
    return 0;
  }
  for (int i = 1; i <= n; i++) {
    for (int j = i + 1; j <= n && a[i] != b[i]; j++) {
      if (color[i] != color[j]) continue;
      if (a[i] > b[i] && a[j] < b[j]) {
        findpath(i, j);
        solve(i, j, std::min(a[i] - b[i], b[j] - a[j]));
      } else if (a[i] < b[i] && a[j] > b[j]) {
        findpath(j, i);
        solve(j, i, std::min(a[j] - b[j], b[i] - a[i]));
      }
    }
  }
  printf("%d\n", res);
  for (int i = 0; i < res; i++)
    printf("%d %d %d\n", ans[i][0], ans[i][1], ans[i][2]);
  return 0;
}
View Code

 

posted @ 2020-02-01 17:16  Mrzdtz220  阅读(139)  评论(0编辑  收藏  举报