• UVA 100


    100 - The 3n+1 problem (3n+1 问题)


    /*
    * 100 - The 3n+1 problem (3n+1 问题)
    * 作者 仪冰
    * QQ 974817955
    *
    * [问题描述]
    * 考虑如下的序列生成算法:从整数 n 开始,如果 n 是偶数,把它除以 2;如果 n 是奇数,
    * 把它乘 3 加1。用新得到的值重复上述步骤,直到 n = 1 时停止。
    * 例如,n = 22 时该算法生成的序列是:
    * 22,11,34,17,52,26,13,40,20,10,5,16,8,4,2,1
    * 人们猜想(没有得到证明)对于任意整数 n,该算法总能终止于 n = 1。
    * 这个猜想对于至少 1 000 000 内的整数都是正确的。
    * 对于给定的 n,该序列的元素(包括 1)个数被称为 n 的循环节长度。
    * 在上述例子中,22 的循环节长度为 16。
    * 输入两个数 i 和 j,你的任务是计算 i 到 j(包含 i 和 j)之间的整数中,
    * 循环节长度的最大值。
    
    * [输入]
    * 输入每行包含两个整数 i 和 j。所有整数大于 0,小于 1 000 000。
    *
    * [输出]
    * 对于每对整数 i 和 j,按原来的顺序输出 i 和 j,然后输出二者之间的整数中的最大循环节长度。
    * 这三个整数应该用单个空格隔开,且在同一行输出。
    * 对于读入的每一组数据,在输出中应位于单独的一行。
    *
    [样例输入]
    1 10
    100 200
    201 210
    900 1000
    
    [样例输出]
    1 10 20
    100 200 125
    201 200 27
    900 1000 174
    
    * [解题方法]
    * 计算每个数的循环节长度,求给定区间的最大值。
    *
    * 需要注意:
    * 1.中间计算过程有的数据会超出int 或 long 型范围,应该用long long型。
    * 2.输入的两个数,应该比较大小,判断出左区间和右区间。
    * 3.直接按部就班的计算会time limited(超时),这里采用填表的方法,
    *   把算出来的结果保存在一个全局数组中,这样以后用到的时候,直接拿来用,节省时间,避免超时。
    */
    
    #include<iostream>
    #include<cstring>
    
    using namespace std;
    
    const int MAXN = 1000000;  //右端点最大值
    
    int MediaVariableArray[MAXN];  //保存区间中所有的循环节长度,这是对填表的应用
    
    int LoopNodeLength (long long EveryNumber);  //计算循环节长度
    
    int main()
    {
        int firstnumber = 0;        //输入的第一个数
        int secondnumber = 0;       //输入的第二个数
        int nodeleft = 0;           //区间左端点
        int noderight = 0;          //区间右端点
        int loopnodemax = 0;        //保存最大长度的循环节
        int everynodelength = 0;    //保存区间中单个数的循环节长度
    
        memset(MediaVariableArray, 0, sizeof(MediaVariableArray)); //初始化,都置为0
    
        while (cin >> firstnumber >> secondnumber)
        {
            if (firstnumber > secondnumber)  //判断左端点和右端点
            {
                nodeleft = secondnumber;
                noderight = firstnumber;
            }
            else
            {
                nodeleft = firstnumber;
                noderight = secondnumber;
            }
    
            loopnodemax = 0; //初始化最大值
            for (int i=nodeleft; i<=noderight; i++)
            {
                everynodelength = LoopNodeLength(i);
    
                if (everynodelength > loopnodemax) //判断是否更新最大值
                {
                    loopnodemax = everynodelength;
                }
            }
    
            cout << firstnumber << " " <<secondnumber << " ";
            cout << loopnodemax << endl;
        }
    
        return 0;
    }
    
    int LoopNodeLength(long long EveryNumber)
    {
        if (EveryNumber == 1)
        {
            return 1;
        }
    
        if (EveryNumber & 1)  //按位与1 等价于 对2求模;左移 等价于 乘以2,同理右移是除以2。
        {
            //计算n = 3n + 1;
            //左移运算符比加号优先级低,所以加括号;
            //我建议不管怎样,为了代码易读都应该加上必要的括号。
            EveryNumber = EveryNumber + (EveryNumber<<1) + 1;
        }
        else
        {
            EveryNumber >>= 1;  //n = n / 2
        }
    
        //如果中间计算值小于MAXN就看看我们先前求没求出它的循环节长度,
        //如果求出来了,直接拿来用,节省时间。
        if (EveryNumber < MAXN)
        {
            if (MediaVariableArray[EveryNumber] == 0)
            {
                MediaVariableArray[EveryNumber] = LoopNodeLength(EveryNumber);
            }
    
            return MediaVariableArray[EveryNumber] + 1;
        }
    
        return LoopNodeLength(EveryNumber) + 1;
    }
    


  • 相关阅读:
    多姿多彩的线程
    字典操作
    字符串语法
    购物车
    列表常用语法
    整数划分问题
    计算N的阶层
    判断是否是素数
    快速排序
    冒泡排序
  • 原文地址:https://www.cnblogs.com/riskyer/p/3339421.html
Copyright © 2020-2023  润新知