如果一個數 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;
}