Problem T3. 高中题

由于好路只会减少权值 $\delta_a$,坏路会增加权值 $\delta_b$
考虑这样一个不等式

$$ w_a-\delta _a\leq w_b+\delta _b $$

移项可得

$$ w_a-w_b\leq \delta_a+\delta_b $$

左边为边权,右边为顶标和。

用 KM 计算出顶标。

#include <bits/stdc++.h>

using namespace std;

const int N = 400;

int g[N][N];

int main() {
  int n, m;
  cin >> n >> m; 
  vector<int> weight(m);
  vector<vector<pair<int, int>>> graph(n); 
  for (int i = 0; i < n - 1; ++i) {
    int u, v, w; 
    cin >> u >> v >> w; 
    --u, --v; 
    weight[i] = w; 
    graph[u].emplace_back(v, i);
    graph[v].emplace_back(u, i);  
  }
  for (int i = n - 1; i < m; ++i) {
    int u, v, w; 
    cin >> u >> v >> w; 
    --u, --v; 
    weight[i] = w; 
    vector<int> vis(n, 0); 
    function<bool(int u, int goal)> dfs = [&](int u, int goal) {
      vis[u] = 1; 
      if (u == goal) {
        return true; 
      }
      for (auto e : graph[u]) {
        int v = e.first, id = e.second;
        if (vis[v]) {
          continue;
        }
        if (dfs(v, goal)) {
          if (weight[id] > w) {
            g[id][i - n + 1] = weight[id] - w; 
          }
          return true; 
        }
      }
      return false; 
    };
    dfs(u, v); 
  }
  auto km = [&]() {
    int N = max(n - 1, m - n + 1); 
    vector<bool> visx(N);
    vector<bool> visy(N); 
    vector<int> match(N); 
    vector<int> slack(N); 
    vector<int> valx(N); 
    vector<int> valy(N); 
    fill(match.begin(), match.end(), -1);
    for (int i = 0; i < N; ++i) {
      valx[i] = valy[i] = 0; 
      for (int j = 0; j < N; ++j) {
        valx[i] = max(valx[i], g[i][j]); 
      }
    }
    for (int i = 0; i < N; ++i) {
      fill(slack.begin(), slack.end(), 0x3f3f3f3f);
      while (true) {
        fill(visx.begin(), visx.end(), 0);
        fill(visy.begin(), visy.end(), 0); 
        function<bool(int u)> dfs = [&](int u) {
          visx[u] = 1; 
          for (int v = 0; v < N; ++v) {
            int w = g[u][v];  
            if (visy[v]) {
              continue; 
            }
            if (valx[u] + valy[v] - w == 0) {
              visy[v] = true; 
              if (match[v] == -1 || dfs(match[v])) {
                match[v] = u; 
                return true; 
              } 
            } else {
              slack[v] = min(slack[v], valx[u] + valy[v] - w); 
            }
          }
          return false; 
        };
        if (dfs(i)) {
          break; 
        }
        int d = 0x3f3f3f3f;
        for (int j = 0; j < N; ++j) {
          if (!visy[j]) {
            d = min(d, slack[j]); 
          }
        }
        for (int j = 0; j < N; ++j) {
          if (visx[j]) {
            valx[j] -= d; 
          }
          if (visy[j]) {
            valy[j] += d; 
          } else {
            slack[j] -= d; 
          }
        }
      } 
    } 
    int ans = 0; 
    for (int i = 0; i < m; ++i) {
      ans += (i < n - 1 ? valx[i] : valy[i - n + 1]); 
    }
    cout << ans << '\n';
  };
  km(); 
  return 0; 
}
最后修改:2020 年 08 月 27 日 12 : 57 AM
如果觉得我的文章对你有用,请随意赞赏