一本通 数字转换 (树的直径 两种求法)

【定义】我们将一棵树T = ( V,E )的直径定义为maxδ ( u,v ) ( u,v ∈ V ),也就是说,树中所有最短路径距离的最大值即为树的直径。对于这类问题,我们主要有两种求解方法。 我们拿一个题目当例子:题目链接题意:若是一个数x的所有约数(不包括他自己)之和sum比他自己小,那么x可以转化成sum,sum也可以成 x。例如 4可以变为 3,1可以变为7限制所有数字在不超过n的正整数范围内转换,求数字变换满足无重复数字情况下的最多变换步数 。当n=7,最长为 4->3>
摘要由CSDN通过智能技术生成

【定义】
我们将一棵树T = ( V,E )的直径定义为maxδ ( u,v ) ( u,v ∈ V ),也就是说,树中所有最短路径距离的最大值即为树的直径。

对于这类问题,我们主要有两种求解方法。 我们拿一个题目当例子:
题目链接

题意:若是一个数x的所有约数(不包括他自己)之和sum比他自己小,
那么x可以转化成sum,sum也可以成 x。例如 4可以变为 3,1可以变为7
限制所有数字在不超过n的正整数范围内转换,求数字变换满足无重复数字情况下的最多变换步数 。当n=7,最长为 4->3>1>7

解法1,树形dp
我们令f1[rt]表示以rt为根的树,根节点到叶节点的最长距离 , f2[rt]表示以rt为根的树 , 根节点到叶节点的次最长距离 ,并且这个叶节点和最长距离的那个叶节点不在同一个子树中。

那么易知(好吧是因为我不会证明qaq)树的直径D=max(f1[i]+f2[i])
很明显叶子节点就是边界,递推过程就是叶->根。

设j为i的孩子节点,
如果 f1[j]+w[i][j]>f1[i] 那么f2[i]=f1[i] ,f1[i]=f1[j]+w[i][j]

否则,如果f1[j]+w[i][j]>f2[i] 那么f2[i]=f1[j]+w[i][j]
(注意://这里由于是不同的子树j不断更新i,所以可以保证f1[i] f2[i] 不会走同一个子树)
简而言之就是,
孩子节点+距离如果能更新最长链,次长链就更新为原先最长链的值,最长链就被孩子节点更新。 如果不能,就看看能不能更新次长链。

题目代码:

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<stdlib.h>
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<stdlib.h>
#include<string.h>
#include<string>
#include<vector>
#include<stack>
#include<queue>
#include<map>
#include<math.h>
#include<set>
using namespace std;
#define LL long long
#define ULL unsigned long long
const int INF=0x3f3f3f;
const double eps=1e-5;
const int maxn=5e4+10;
/*题意:若是一个数x的所有约数(不包括他自己)之和sum比他自己小,
那么x可以转化成sum,sum也可以成 x。例如 4可以变为 3,1可以变为7
限制所有数字变换在不跨越 n的正整数范围内举行转化,求不停举行数字变换且无重复数字的最多变换步数*/
int sum[maxn];//预处理每个数的约数之和
int f1[maxn],f2[maxn];//f1:以i为根的树中,i到叶子节点的最长距离,f2 :....次长距离
//直径就是 max(f1[i]+f2[i])  就是树中所有的两点最短距离中的最大值
//
int n;
void getsum(
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值