题目想法
这是Rinne Loves Edges的扩展版, 依然是剪掉一些路径从而达到题目要求, 但多了一重限制, 不过不影响核心思路
题目要求
要剪去所有叶子结点路径(可以剪去叶子结点, 也可以剪去叶子结点的某个根结点), 并且总权值要小于等于m. 而题目要求的结果为 求剪去所有叶子结点且总权值小于等于m的所有方案中, 最长边最短的值
题目思路
二分求最优解, 典型二分思路, 每次二分最长边的值, 即最长边为x时, 剪去叶子结点总权值是否小于等于m, 若满足条件则更新res答案值
注意如果最大值INF设为0x3f3f3f3f, 要用到long long, 不然会爆, 所以我的代码中设为的1e7 + 10, 因为懒得改long long了
代码实现
#include <bits/stdc++.h>
#define INF 1e7 + 10
using namespace std;
const int N = 1010, M = N * 2;
int n, m;
int e[M], w[M], ne[M], h[N], idx;
int f[N];
void add(int a, int b, int c)
{
e[idx] = b, ne[idx] = h[a], w[idx] = c, h[a] = idx ++ ;
}
void dfs(int u, int father, int x)
{
bool is_leaf = true;
for (int i = h[u]; i != -1; i = ne[i])
{
int j = e[i];
if (j == father) continue;
dfs(j, u, x);
is_leaf = false;
f[u] += min(f[j], w[i] > x ? f[j] : w[i]);
}
if (is_leaf) f[u] = INF;
}
int main()
{
scanf("%d%d", &n, &m);
memset(h, -1, sizeof h);
for (int i = 0; i < n - 1; i ++ )
{
int a, b, c;
scanf("%d%d%d", &a, &b, &c);
add(a, b, c), add(b, a, c);
}
int l = 0, r = 1e6 + 10;
int res = 0;
while (l < r)
{
int mid = l + r >> 1;
memset(f, 0, sizeof f);
dfs(1, -1, mid);
if (f[1] <= m) r = mid, res = r;
else l = mid + 1;
}
if (!res) puts("-1");
else printf("%d\n", res);
return 0;
}
京公网安备 11010502036488号