题目描述
对一个十进制数的各位数字做一次平方和,称作一次迭代。如果一个十进制数能通过若干次迭代得到 \(1\),就称该数为幸福数。\(1\) 是一个幸福数。此外,例如 \(19\) 经过一次迭代得到 \(82\) ,二次迭代后得到 \(68\),3 次迭代后得到 100,最后得到 \(1\)。则 \(19\) 就是幸福数。显然,在一个幸福数迭代到 \(1\) 的过程中经过的数字都是幸福数,它们的幸福是依附于初始数字的。例如 \(82、68、100\) 的幸福是依附于 \(19\) 的。而一个特立独行的幸福数,是在一个有限的区间内不依附于任何其它数字的;其独立性就是依附于它的的幸福数的个数。如果这个数还是个素数,则其独立性加倍。例如 \(19\) 在区间 \([1, 100]\) 内就是一个特立独行的幸福数,其独立性为 \(2 × 4 = 8\)。
另一方面,如果一个大于1的数字经过数次迭代后进入了死循环,那这个数就不幸福。例如 \(29\) 迭代得到 $85、89、145、42、20、4、16、37、58、89、…… $可见 \(89\) 到 \(58\) 形成了死循环,所以 \(29\) 就不幸福。
本题就要求你编写程序,列出给定区间内的所有特立独行的幸福数和它的独立性。
输入格式
输入在第一行给出闭区间的两个端点:\(1 < A < B ≤ 10^4\)
输出格式:
按递增顺序列出给定闭区间 \([A,B]\) 内的所有特立独行的幸福数和它的独立性。每对数字占一行,数字间以 \(1\) 个空格分隔。
如果区间内没有幸福数,则在一行中输出 SAD
。
输入输出样例
输入 #1
10 40
输出 #1
19 8
23 6
28 3
31 4
32 3
输入 #2
110 120
输出 #2
SAD
说明/提示
在样例#1中,\(10、13\) 也都是幸福数,但它们分别依附于其他数字(如 \(23、31\) 等等),所以不输出。其它数字虽然其实也依附于其它幸福数,但因为那些数字不在给定区间 \([10,40]\) 内,所以它们在给定区间内是特立独行的幸福数。
————————————————————————————————————
首先会想到把每个数字抽象成节点,每个节点根据题目给的迭代方式连接到后继节点上。
由于这个过程是难逆的,而在某数不断迭代之后只可能有两个结果。
(1)变换成数字 \(1\),路径上都是幸福数 (2)出现环,路径上都是不幸福数
所以我们不妨把数字 \(1\) 所在节点视为根节点,然后每一次迭代就变成了“找父亲”的过程。
由于父亲幸福或不幸福会影响到儿子(父亲依赖于儿子),所以我们只要在递归中不断让儿子继承父亲的状态再维护一下到根的距离即可。
如果打表一下可以发现只会有一个环出现,即题目给的那个环,但我这里直接忽略了这个直接标记着找环了。
代码如下:
#include <bits/stdc++.h>
#define MAXN 100007
using namespace std;
int a,b,cnt,dep[MAXN],ty[MAXN],prime[MAXN];
bool fl,rd[MAXN],vis[MAXN],isp[MAXN];
//ty = 0 未访问 1 幸福数 2 不幸福数
//rd = true 特立独行(入度为零) false 非特立独行(入度大于零)
//vis 是用来判断环的 vis = 1 表示该元素之前在递归栈中出现过
//dep 保存着到1号节点的深度 即变换成1需要的次数
//线性筛质数 isp 保存一个数是否为质数
//也可以最后用 O(sqrt) 的时间判定质数,但是理论复杂度会上升
inline void init() {
memset(isp,1,sizeof(isp));
isp[0]=isp[1]=false;
for (int i=2;i<MAXN;i++) {
if (isp[i]) prime[++cnt]=i;
for(int j=1;j<=cnt && i*prime[j]<MAXN;j++) {
isp[i*prime[j]]=false;
if (!(i%prime[j])) break;
}
}
}
//计算下一次迭代的函数
inline int nxt(int x) {
int ret=0;
while (x) ret+=(x%10)*(x%10),x/=10;
return ret;
}
//核心的递归函数
inline void search(int x) {
int to=nxt(x); vis[x]=true; //把出现过的数都用vis标记下 下次如果再遇到这个数即有环(不幸福)
if ((vis[to] && !ty[to]) || ty[to]==2) ty[x]=2; //后继(父亲)若不幸福 当前节点也不幸福
else if (ty[to]==1) ty[x]=1; //后继(父亲)若幸福,当前节点也幸福
else search(to),ty[x]=ty[to]; //后继的状态未知 则递归找一下
rd[to]=true,dep[x]=dep[to]+1; //把有前驱的节点标记成不特立独行的 累加到1(根节点)的深度
}
int main() {
init(); ty[1]=1; //初始化 1显然是幸福的
scanf("%d%d",&a,&b);
for (int i=a;i<=b;i++) if (!ty[i]) search(i); //如果状态未知 则递归找一下
for (int i=a;i<=b;i++)
if (ty[i]==1 && !rd[i]) //若同时满足特立独行和幸福
printf("%d %d\n",i,isp[i]?dep[i]*2:dep[i]),fl=true;
if (!fl) puts("SAD"); //SO SAD
return 0;
}
原文地址:https://www.cnblogs.com/zhwer/p/12256471.html