给一棵树,每条边有权。求一条简单路径,权值和等于 K ,且边的数量最小。
分析
显然这题是点分治。
我们设 f[i] 表示当前的子树中,距离 rt 为 i 的最短距离,每次在求出 rt 到它子树内的所有 dis 并同时将子树中的节点加入栈 s 中,然后对 ans 取 min ,设 dep[i] 表示 i 在 rt 的子树中的深度,我们便令 ans = min(ans, f[k-dis[s[i]]] + dep[s[i]]) ,然后再更新 f[i] , f[dis[s[i]]] = min(f[dis[s[i]]], dep[s[i]]) 。
代码
//=========================
// author:hliwen
// date:2020.1.19
//=========================
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define N 200005
#define M 1000003
#define INF 0x3f3f3f3f
#define DEBUG puts("ok")
#define tie0 cin.tie(0),cout.tie(0)
#define fastio ios::sync_with_stdio(false)
#define File(x) freopen(x".in","r",stdin);freopen(x".out","w",stdout)
using namespace std;
typedef long long ll;
template <typename T> inline void read(T &x) {
T f = 1; x = 0; char c;
for (c = getchar(); !isdigit(c); c = getchar()) if (c == '-') f = -1;
for ( ; isdigit(c); c = getchar()) x = x * 10 + (c ^ 48);
x *= f;
}
int n, k, size, rt, ans, tot, num;
int to[N<<1], nxt[N<<1], val[N<<1], head[N<<1], cnt;
int son[N], sz[N], dis[N], f[M], st[N], s[N], dep[N];
bool vis[N];
void insert(int u, int v, int w) {
to[++cnt] = v, val[cnt] = w, nxt[cnt] = head[u], head[u] = cnt;
}
void dfs_root(int u, int fa) {
sz[u] = 1, son[u] = 0;
for (int i = head[u]; i; i = nxt[i]) {
int v = to[i];
if (v == fa || vis[v]) continue;
dfs_root(v, u);
sz[u] += sz[v];
son[u] = max(son[u], sz[v]);
}
son[u] = max(son[u], size - sz[u]);
if (son[rt] > son[u]) rt = u;
}
void dfs_dis(int u, int fa, int len) {
dis[u] = len, dep[u] = dep[fa] + 1, s[++tot] = u;
for (int i = head[u]; i; i = nxt[i]) {
int v = to[i], w = val[i];
if (vis[v] || v == fa) continue;
dfs_dis(v, u, len + w);
}
}
void solve(int u) {
num = f[0] = dep[u] = 0;
for (int i = head[u]; i; i = nxt[i]) {
int v = to[i], w = val[i];
if (vis[v]) continue;
tot = 0;
dfs_dis(v, u, w);
for (int j = 1; j <= tot; ++j)
if (dis[s[j]] <= k)
ans = min(ans, f[k-dis[s[j]]] + dep[s[j]]);
for (int j = 1; j <= tot; ++j)
if (dis[s[j]] <= k) {
f[dis[s[j]]] = min(f[dis[s[j]]], dep[s[j]]);
st[++num] = dis[s[j]];
}
}
for (int i = 1; i <= num; ++i) f[st[i]] = INF;
}
void divide(int u) {
vis[u] = 1;
solve(u);
for (int i = head[u]; i; i = nxt[i]) {
int v = to[i];
if (vis[v]) continue;
size = sz[v], rt = 0;
dfs_root(v, u);
divide(rt);
}
}
int main() {
int u, v, w;
memset(f, INF, sizeof f);
read(n), read(k);
for (int i = 1; i < n; ++i) {
read(u), read(v), read(w);
insert(u + 1, v + 1, w), insert(v + 1, u + 1, w);
}
rt = 0, son[0] = size = n, ans = n + 1;
dfs_root(1, 0);
divide(rt);
if (ans >= n + 1) puts("-1");
else printf("%d", ans);
return 0;
}