抽象成求树的直径的问题,求树的直径
在符合条件的数值和他的约数之和之间建立一条边,则原问题就转化成在森林里求树的最长直径,并输出该树的直径
建图时建立有向图即可,每条边由数值x的约数之和sum指向x,因为每个数的约数之和是唯一的,而一个数可以是很多数的约数之和
#include <iostream>
#include <cstring>
const int N = 50005;
int n;
int h[N], e[N], ne[N], idx;
int sum[N];
int res;
void add(int a, int b) {
e[idx] = b, ne[idx] = h[a], h[a] = idx ++ ;
}
int dfs(int u) {
int d1 = 0, d2 = 0;
for (int i = h[u]; ~i; i = ne[i]) {
int j = e[i];
int d = dfs(j) + 1;
if (d >= d1) d2 = d1, d1 = d;
else if (d > d2) d2 = d;
}
res = std::max(res, d1 + d2);
return d1;
}
int main() {
std::cin >> n;
memset(h, -1, sizeof h);
// 求所有i的倍数,i一定是i*j的约数,所以i*j的约数之和每次+=i即可
for (int i = 1; i <= n; i ++ )
for (int j = 2; j <= n / i; j ++ )
sum[i * j] += i;
for (int i = 2; i <= n; i ++ )
if (sum[i] < i)
add(sum[i], i);
// for (int i = 1; i <= n; i ++ ) dfs(i);
// 直接dfs(1)即可
dfs(1);
std::cout << res << '\n';
return 0;
}