【定义】
我们将一棵树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(