PTA L2-029 | 特立独行的幸福 (打表+递归)

题目描述

对一个十进制数的各位数字做一次平方和,称作一次迭代。如果一个十进制数能通过若干次迭代得到 \(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

时间: 2024-11-10 14:44:13

PTA L2-029 | 特立独行的幸福 (打表+递归)的相关文章

2019年GPLT L2-1 特立独行的幸福 比赛题解 中国高校计算机大赛-团体程序设计天梯赛题解

对一个十进制数的各位数字做一次平方和,称作一次迭代.如果一个十进制数能通过若干次迭代得到 1,就称该数为幸福数.1 是一个幸福数.此外,例如 19 经过 1 次迭代得到 82,2 次迭代后得到 68,3 次迭代后得到 100,最后得到 1.则 19 就是幸福数.显然,在一个幸福数迭代到 1 的过程中经过的数字都是幸福数,它们的幸福是依附于初始数字的.例如 82.68.100 的幸福是依附于 19 的.而一个特立独行的幸福数,是在一个有限的区间内不依附于任何其它数字的:其独立性就是依附于它的的幸福

九九乘法表[递归]

#include <iostream> using namespace std; void draw(int n,int x) { if(x<=n) { cout<<n<<"*"<<x<<"="<<n*x<<" "; draw(n,x+1); } } void draw(int n) { if(n>0) { draw(n-1); draw(n,1);

L2-特立独行的幸福

对一个十进制数的各位数字做一次平方和,称作一次迭代.如果一个十进制数能通过若干次迭代得到 1,就称该数为幸福数.1 是一个幸福数.此外,例如 19 经过 1 次迭代得到 82,2 次迭代后得到 68,3 次迭代后得到 100,最后得到 1.则 19 就是幸福数.显然,在一个幸福数迭代到 1 的过程中经过的数字都是幸福数,它们的幸福是依附于初始数字的.例如 82.68.100 的幸福是依附于 19 的.而一个特立独行的幸福数,是在一个有限的区间内不依附于任何其它数字的:其独立性就是依附于它的的幸福

SDNLAB技术分享(四):利用ODL下发流表创建VxLAN网络

邓晓涛,当前就职于江苏省未来网络创新研究院,是CDN团队的一名研发人员,主要从事SDN相关的研发相关工作.曾就职于三星电子于先行解决方案研发组任高级工程师.思科系统于云协作应用技术部(CCATG)任工程师.-----------------------------------------------------------------------------------------------------[分享正文]今天想跟大家分享如何通过ODL控制器下发流表来创建VxLAN网络.ODL作为当前

顺序表实现增,删,查与合并操作

C语言实现顺序表的的基本操作 1.顺序表实现按照位置查找 #include <stdio.h> #include <stdlib.h> #define MAX_SIZE 20 // 需求: // 线性表查找之:按序号查找. // 表中的元素是顺序存放的,故核心语句应该是l.elem[i-1] // 定义一个顺序表 // 应该定义在外面,否则函数头声明访问不到 typedef struct{ int elem[MAX_SIZE]; int last; } SeqList; // 函数

redis 系列7 数据结构之跳跃表

一.概述 跳跃表(skiplist)是一种有序数据结构,它通过在每个节点中维持多个指向其他节点的指针,从而达到快速访问节点的目的.在大部分情况下,跳跃表的效率可以和平衡树(关系型数据库的索引就是平衡树结构)相媲美,并且因为跳跃表的实现比平衡树要来得更为简单,所以有不少程序使用跳跃表来代替平衡树. Redis使用跳跃表作为"有序集合键"的底层实现之一,如果一个有序集合包含的元素数量比较多,又或者有序集合中元素的成员是比较长的字符串时,Redis就会使用跳跃表来作为有序集合键的底层实现.

广义表的实现(法二)

#include<iostream> #include<string> using namespace std; enum elemTag {ATOM,LIST}; class GList; class GLnode { private: elemTag Tag; //标志是原子还是子表 0:原子 1:子表 union { char data; //原子结点值域 struct //表结点指针域 { GLnode *hp; GLnode *tp; }ptr; }; friend cl

广义表 的实现

广义表是非线性结构,其定义是递归的. 以下给出几种简单的广义表模型: 由上图我们可以看到,广义表的节点类型无非head.value.sub三种,这里设置枚举类型,利用枚举变量来记录每个节点的类型: enum  Type { HEAD,   //头节点 VALUE,  //值节点 SUB,    //子表节点 }; 每个节点都有自己的类型以及next指针,除此之外,如果该节点是VALUE类型还要分配空间存储该节点的有效值:但是若该节点是SUB类型,就需定义一个指针指向子表的头. 这里我们可以用联合

广义表总结

/**********************          WZ  ASUST 2016 表的实现与表头表尾问题 缺函数:找值 **********************/ #include<iostream> #include<assert.h> #include<string> using namespace std;   //实现广义表的结构 // 节点的类型:来代替直接写3类 结构体 enum Type//枚举类型 {     HEAD,     VAL