如果一个数 x 的约数之和 y(不包括他本身)比他本身小,那么 x 可以变成 y,y 也可以变成 x。
例如,4 可以变为 3,1 可以变为 7。
限定所有数字变换在不超过 n 的正整数范围内进行,求不断进行数字变换且不出现重复数字的最多变换步数。
输入格式
输入一个正整数 n。
输出格式
输出不断进行数字变换且不出现重复数字的最多变换步数。
数据范围
1≤n≤50000
输入样例:
7
输出样例:
3
样例解释
一种方案为:4→3→1→7。
分析:每一个x最多向它的约数之和y连一条边,每一个点x最多有一个父节点,y是x的父节点,则y与x之间的连线会构成一棵树(y->x,以1为根节点的树)
另外,在求解每个x的约数之和y时,可用筛法求解
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 50000+10;
int sum[N];
int head[N],nexts[N*2],ver[N*2],edge[N*2];
int tot,ans;
void add(int x,int y){
ver[++tot]=y;
nexts[tot]=head[x],head[x]=tot;
}
int dfs(int x){
int d1=0,d2=0;
for(int i=head[x];i;i=nexts[i]){
int y=ver[i];
int d=dfs(y)+1;
if(d>d1){
d2=d1;
d1=d;
}
else if(d>d2){
d2=d;
}
}
ans=max(ans,d1+d2);
return d1;
}
int main(){
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++){
//j从2开始循环,所以sum[i]不会加上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);
}
}
dfs(1);
printf("%d",ans);
return 0;
}