PAT乙级-1005-继续(3*n + 1)猜想

该篇博客介绍了PAT乙级编程竞赛中关于卡拉兹猜想的题目,重点在于理解如何避免重复计算并找到关键数字。博主通过样例解释了数列递推的过程,提出了使用数组记录递推状态的方法,并展示了两种不同的排序方式以满足从大到小输出关键数字的要求。此外,还提供了完整的C++代码示例。
摘要由CSDN通过智能技术生成

PAT乙级-1005-继续(3*n + 1)猜想

卡拉兹(Callatz)猜想已经在1001中给出了描述。在这个题目里,情况稍微有些复杂。

当我们验证卡拉兹猜想的时候,为了避免重复计算,可以记录下递推过程中遇到的每一个数。例如对 n=3 进行验证的时候,我们需要计算 3、5、8、4、2、1,则当我们对 n=5、8、4、2 进行验证的时候,就可以直接判定卡拉兹猜想的真伪,而不需要重复计算,因为这 4 个数已经在验证3的时候遇到过了,我们称 5、8、4、2 是被 3“覆盖”的数。我们称一个数列中的某个数 n 为“关键数”,如果 n 不能被数列中的其他数字所覆盖。

现在给定一系列待验证的数字,我们只需要验证其中的几个关键数,就可以不必再重复验证余下的数字。你的任务就是找出这些关键数字,并按从大到小的顺序输出它们。

输入格式

每个测试输入包含 1 个测试用例,第 1 行给出一个正整数 K (<100),第 2 行给出 K 个互不相同的待验证的正整数 n (1<n≤100)的值,数字间用空格隔开。

输出格式

每个测试用例的输出占一行,按从大到小的顺序输出关键数字。数字间用 1 个空格隔开,但一行中最后一个数字后没有空格。

输入样例

6
3 5 6 7 8 11

输出样例

7 6

解题思路

用输入样例中的数进行递推可发现:
3 递推: ->5->8->4->2->1
5 递推: ->(在3递推中已出现5)
6 递推: ->3
7 递推: ->11->17->->26->13->20->10->5
8 递推: ->
11递推 :->

经观察可发现,关键数字在递推中不会出现(输入样例中的6,7),而其余数(3, 5, 8, 11)均会在递推过程中复现。

因此:
可以设置一个数组arr[10000 ],递推过程中出现的数n,可将其对应的下标数设为1来标记,即:

//递推中出现的数标记为0
arr[n] = 1;
//以样例数n作为下标,若arr[n] != 1,则说明n是关键数

这样最终将输入样例作为下标,把数组arr[ ]中不为1的项输出即可。
注意:题目要求从大到小输出,所以最后进行一个排序。
这里采用algorithm库下的sort方法。
有两种写法
法1:

bool cmp(int a, int b) {return a > b;}
sort(v.begin(), v.end(), cmp);

法2:

sort(v.begin(), v.end(), greater<int>());

完整代码

#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;

int arr[10000];
bool cmp(int a, int b) {return a > b;}

int main() {
    int k, n, flag = 0;
    cin >> k;
    vector<int> v(k);
    for (int i = 0; i < k; i++) {
        cin >> n;
        v[i] = n;
        while (n != 1) {
            if (n % 2 != 0) n = 3 * n + 1;
            n = n / 2;
            // 每个数字n用数组中arr[n]记录,当运算过程中出现了,就将值设成1
            if (arr[n] == 1) break;
            arr[n] = 1;
        }
    }
    /**
     * 输入:6
            3 5 6 7 8 11
     * 经过sort排序后,v[5] = {11, 8, 7, 6, 5, 3}, size = 6;
     * 通过找规律可以发现,凡是一组数中的关键数,在递推过程中不会出现
     * 例如上述输入的梯队过程如有:
     * 3->5->8->4->2->1
     * 5->
     * 6->3
     * 7->11->17->->26->13->20->10->5
     * 8->
     * 11->
     *
     * 在给梯队过程中出现的每一个数n,设置arr[n] = 1的过程中
     * 初始数不会计入,即3->5->8...这一项,arr[3]不会改变,是从arr[5] = 1开始的
     *
     * 所以关键数的arr[n] = 0
     * 所以当v[i]为关键数时,
     * arr[v[i]] = 0;
     */

    //排序是因为题目要求从大到小输出
    //也可以这样写:
    //sort(v.begin(), v.end(), greater<int>());
    sort(v.begin(), v.end(), cmp);
    for (int i = 0; i < v.size(); i++) {
        if (arr[v[i]] == 0) {
            if (flag == 1) cout << " ";
            cout << v[i];
            flag = 1;
        }
    }
    return 0;
}

参考:

柳婼:https://www.liuchuo.net/archives/455

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值