Problem T3. 高中题
由于好路只会减少权值 (delta_a),坏路会增加权值 (delta_b)
考虑这样一个不等式
[w_a-delta _aleq w_b+delta _b
]
移项可得
[w_a-w_bleq 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 << '
';
};
km();
return 0;
}