洛谷 P3629 [APIO2010]巡逻(树的直径)
时间:2020-10-16
本文章向大家介绍洛谷 P3629 [APIO2010]巡逻(树的直径),主要包括洛谷 P3629 [APIO2010]巡逻(树的直径)使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
题目链接:https://www.luogu.com.cn/problem/P3629
首先如果不添加任何道路,每条边会经过两次,那么所经过的路径长度应该是2*(n-1)。
分析可得,当添加一条道路时,会形成一个环,这个环上且属于原来树上的点只会经过一次。所以可以将直径的两个端点连起来,会使减小的路径最大。
因此可以得到k=1的思路:两次DFS求出树的直径d,输出2*(n-1)-(d-1)。
当添加两条道路时,又会形成一个环,如果两个环不相交,那么答案会继续减小,但是环可能会重合,而对于重合的部分,还是要经过两次。
所以可以得到k=2的思路:两次DFS求出原数的直径d1,并记录路径。将直径上的所有边权改为-1,表示如果这样走就与第一个环重复,并且在最后答案统计的时候相当于把重合的部分加了回来。用树形DP求树的直径长度d2。
(注意第一次只能用DFS,因为要记录路径,而第二次只能用树形DP,因为有负边权,距离点u远的点不一定真的远)。
最终的答案即为2*(n-1)-(d1-1)-(d2-1)。
注意边权要赋在边上,虽然比较难写:主要在求出d1的路径后,将这个路径上的所有边权改为-1。注意边是双向边,要将两个方向的边权都改成-1。
AC代码:
1 #include<cstdio> 2 #include<iostream> 3 #include<queue> 4 #include<cstring> 5 using namespace std; 6 const int N=100005; 7 const int INF=2147483647; 8 int n,k,maxd,tot,head[N],f[N],dis[N],vis[N],p,w[N],ans; 9 struct node{ 10 int to,next,w; 11 }edge[N<<1]; 12 void add(int u,int v,int w){ 13 edge[tot].to=v; 14 edge[tot].next=head[u]; 15 edge[tot].w=w; 16 head[u]=tot++; 17 } 18 void DFS(int u,int fa){ 19 f[u]=fa; 20 if(maxd<dis[u]){ 21 maxd=dis[u]; 22 p=u; 23 } 24 for(int i=head[u];i!=-1;i=edge[i].next){ 25 int v=edge[i].to; 26 if(vis[v]||v==fa) continue; 27 vis[v]=1; 28 dis[v]=dis[u]+edge[i].w; 29 DFS(v,u); 30 } 31 } 32 void DP(int u){ 33 vis[u]=1; 34 for(int i=head[u];i!=-1;i=edge[i].next){ 35 int v=edge[i].to; 36 if(vis[v]) continue; 37 DP(v); 38 ans=max(ans,dis[u]+dis[v]+edge[i].w); 39 dis[u]=max(dis[u],dis[v]+edge[i].w); 40 } 41 } 42 int main(){ 43 memset(head,-1,sizeof(head)); 44 memset(f,-1,sizeof(f)); 45 scanf("%d%d",&n,&k); 46 for(int i=1;i<=n-1;i++){ 47 int a,b; 48 scanf("%d%d",&a,&b); 49 add(a,b,1); add(b,a,1); 50 } 51 int a,b,d1,d2; 52 DFS(1,-1); 53 a=p; 54 maxd=0; 55 memset(dis,0,sizeof(dis)); 56 memset(f,-1,sizeof(f)); 57 memset(vis,0,sizeof(vis)); 58 DFS(p,-1); 59 b=p; 60 d1=maxd; 61 if(k==1){ 62 printf("%d",2*(n-1)-(d1-1)); 63 return 0; 64 } 65 for(int i=b;i!=-1;i=f[i]){ 66 for(int j=head[i];j!=-1;j=edge[j].next){ 67 int v=edge[j].to; 68 if(v==f[i]) edge[j].w=-1; 69 } 70 for(int j=head[f[i]];j!=-1;j=edge[j].next){ 71 int v=edge[j].to; 72 if(v==i) edge[j].w=-1; 73 } 74 } 75 memset(vis,0,sizeof(vis)); 76 memset(dis,0,sizeof(dis)); 77 DP(1); 78 d2=ans; 79 printf("%d\n",2*(n-1)-(d1-1)-(d2-1)); 80 return 0; 81 }
原文地址:https://www.cnblogs.com/New-ljx/p/13828843.html
- golang简单tls协议用法完整示例
- spark开发环境详细教程1:IntelliJ IDEA使用详细说明
- MySQL数据库(五):索引
- hdu----(1466)计算直线的交点数(dp)
- golang模板template自定义函数用法示例
- 程序员你为什么这么累【续】:编写简陋的接口调用框架 - 动态代理学习
- hdu---(Tell me the area)(几何/三角形面积以及圆面积的一些知识)
- MySQL数据库(六):体系结构和存储引擎
- hdu----(2222)Keywords Search(trie树)
- MySQL数据库(七):数据导出与导入
- flume与kafka整合高可靠教程
- Oracle 12c系列(一)|多租户容器数据库
- Spring Security入门(三):密码加密
- MySQL数据库(八):表记录的基本操作(增删改查)
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 方块转换 Transformations
- 回文平方数 Palindromic Squares
- 双重回文数 Dual Palindromes
- 修理牛棚 Barn Repair
- 牛式 Prime Cryptarithm
- 解题报告(牛客OI周赛7-普及组)
- 号码锁 Combination Lock
- 数据结构回顾及展望(一)
- Spring Boot 整合 Quartz 实现 Java 定时任务的动态配置
- 数据结构回顾及展望(二)(3.22更新)
- Windows挂载CFS文件系统
- XMU oj Problem List
- Python入门笔记(安装及初步使用)
- python 入门笔记[语法基础(上)]
- 怎样解决 JavaScript 生态中第三方安全性问题?