当前位置: 首页 > news >正文

洛谷 P3000 [USACO10DEC] Cow Calisthenics G

思路

题目要求断若干条边后形成的连通块中,最大的直径最小,很明显的二分。关键就在于如何写 c h e c k check check 函数了。

可以用 d f s dfs dfs 来判断要断哪条边。

一、 d [ u ] d[u] d[u] 定义

d [ u ] d[u] d[u] 为从 u u u 出发到子树中【断开边后连通块的叶子节点】所经过的最多的节点数,包括 u u u 节点自己。

这句话可能比较难理解。设 v v v u u u 的一个子节点,那么程序会先递归判断以 v v v 为根的子树中哪些边需要被断掉。那么再回朔到 u u u 节点时,子树 v v v 就算一个被删了一些边的连通块,那么子树 v v v 就会有一些新的叶子节点。这些新叶子节点到 u u u 会经过若干节点, d [ u ] d[u] d[u] 就代表【经过节点数最多的】那条路径上的【节点数】。

如此一来, d [ v ] d[v] d[v] 就表示从 v v v 出发到其子树叶子节点经过的最多节点数。同时,它还可以表示节点 u u u 走到【以 v v v 为根的子树的叶子节点】所经过的最多边数。

(本人在看其他题解时想了好一会才想明白,因此花了这么多文字来解释,太菜了)

二、断边条件

现在考虑什么情况断边。

假设 m a x d maxd maxd目前所扫过的所有子节点 v v v d [ ] d[] d[] 值最大的那个。

现在又扫完一个新节点 v ′ v' v:若 m a x d + d [ v ′ ] > l i m i t maxd + d[v'] > limit maxd+d[v]>limit,那就断边;否则用 d [ v ′ ] d[v'] d[v] 更新 m a x d maxd maxd

问题又来了,断边时有两条边可供断开(即: m a x d , d [ v ′ ] maxd, d[v'] maxd,d[v] 分别代表的那一条),该断哪一条?

贪心的想,我们肯定要保留值较小的那一条。因为若保留大的,它未来可能会与其他更多的 d [ ] d[] d[] 相加超出限制,导致更多的断边,这样显然时更劣的。

代码

#include <bits/stdc++.h>using namespace std;const int maxn = 1e5 + 7;int n, m;
vector<int> e[maxn];int d[maxn], cnt;
void dfs(int u, int f, int lim) {if (cnt > m) return ;int maxd = 0;for (int v : e[u]) {if (v == f) continue;dfs(v, u, lim);if (maxd + d[v] > lim)  // 超出限制, 断边, 并保留较小的那一条边 ++cnt, maxd = min(maxd, d[v]);else maxd = max(maxd, d[v]);  // 没有超出限制, 更新 maxd }d[u] = maxd + 1;
}
bool check(int x) {cnt = 0, dfs(1, 0, x);return cnt <= m;
}
int main() {scanf("%d%d", &n, &m);for (int i = 1; i < n; ++i) {int u, v;scanf("%d%d", &u, &v);e[u].push_back(v);e[v].push_back(u);}// 二分最大直径的最小值 int l = 0, r = n - 1;int ans = 0;while (l <= r) {int mid = (l + r) >> 1;if (check(mid)) ans = mid, r = mid - 1;else l = mid + 1;}printf("%d\n", ans);return 0;
} 

若觉得此篇题解过于冗长,可以看看这篇

http://www.lryc.cn/news/518320.html

相关文章:

  • Web渗透测试之XSS跨站脚本攻击 盲打 详解
  • 经典编程题:服务器广播
  • 【网络协议】静态路由详解
  • 朝天椒USB服务器在银泰证券虚拟化超融合场景的应用案例
  • .NET framework、Core和Standard都是什么?
  • FairGuard游戏安全2024年度报告
  • JetBrains IDEs和Visual Studio Code的对比
  • 文件剪切走:深度解析与高效恢复策略
  • Win32汇编学习笔记09.SEH和反调试
  • [人工智能]CSDN创作助手体验
  • vue3中el-table实现多表头并表格合并行或列
  • HTML+CSS+JS制作中国传统节日主题网站(内附源码,含5个页面)
  • 时空笔记:CBEngine(微观交通模拟引擎)
  • 【LeetCode】力扣刷题热题100道(26-30题)附源码 轮转数组 乘积 矩阵 螺旋矩阵 旋转图像(C++)
  • 【C++】字符串的 += 和 + 运算详解
  • 多模态大模型部署:结合dify
  • Matlab Steger提取条纹中心(非极大值抑制)
  • springboot + vue+elementUI图片上传流程
  • LabVIEW 系统诊断
  • 韩国机场WebGIS可视化集合Google遥感影像分析
  • springCloudGateWay使用总结
  • 使用new Vue创建Vue 实例并使用$mount挂载到元素上(包括el选项和$mount区别)
  • GTX750Ti打DP补丁
  • springmvc前端传参,后端接收
  • PyTorch 张量的分块处理介绍
  • 在Ubuntu中使用systemd设置后台自启动服务
  • mongodb清理删除历史数据
  • C++字体库开发之字体回退策略十六
  • IO进程day3
  • 【多线程初阶篇¹】线程理解| 线程和进程的区别