zoukankan      html  css  js  c++  java
  • 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;
    }
    


  • 相关阅读:
    .net core 3.1 使用Redis缓存
    JavaSE 高级 第11节 缓冲输入输出字节流
    JavaSE 高级 第10节 字节数组输出流ByteArrayOutputStream
    JavaSE 高级 第09节 字节数组输入流ByteArrayInputStream
    JavaSE 高级 第08节 文件输出流FileOutputStream
    JavaSE 高级 第07节 文件输入流FileInputStream
    JavaSE 高级 第06节 初识I、O流
    JavaSE 高级 第05节 日期类与格式化
    JavaSE 高级 第04节 StringBuffer类
    JavaSE 高级 第03节 Math类与猜数字游戏
  • 原文地址:https://www.cnblogs.com/riskyer/p/3339421.html
Copyright © 2011-2022 走看看