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

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;

}


 

 

你可能感兴趣的:(uva)