• 【转】UVa Problem 100 The 3n+1 problem (3n+1 问题)——(离线计算)


      1 // The 3n+1 problem (3n+1 问题)
      2 // PC/UVa IDs: 110101/100, Popularity: A, Success rate: low Level: 1
      3 // Verdict: Accepted
      4 // Submission Date: 2011-05-22
      5 // UVa Run Time: 0.032s
      6 //
      7 // 版权所有(C)2011,邱秋。metaphysis # yeah dot net。
      8 //
      9 // [问题描述]
     10 // 考虑如下的序列生成算法:从整数 n 开始,如果 n 是偶数,把它除以 2;如果 n 是奇数,把它乘 3 加
     11 // 1。用新得到的值重复上述步骤,直到 n = 1 时停止。例如,n = 22 时该算法生成的序列是:
     12 //
     13 // 22,11,34,17,52,26,13,40,20,10,5,16,8,4,2,1
     14 //
     15 // 人们猜想(没有得到证明)对于任意整数 n,该算法总能终止于 n = 1。这个猜想对于至少 1 000 000
     16 // 内的整数都是正确的。
     17 //
     18 // 对于给定的 n,该序列的元素(包括 1)个数被称为 n 的循环节长度。在上述例子中,22 的循环节长度
     19 // 为 16。输入两个数 i 和 j,你的任务是计算 i 到 j(包含 i 和 j)之间的整数中,循环节长度的最大
     20 // 值。
     21 //
     22 // [输入]
     23 // 输入每行包含两个整数 i 和 j。所有整数大于 0,小于 1 000 000。
     24 //
     25 // [输出]
     26 // 对于每对整数 i 和 j,按原来的顺序输出 i 和 j,然后输出二者之间的整数中的最大循环节长度。这三
     27 // 个整数应该用单个空格隔开,且在同一行输出。对于读入的每一组数据,在输出中应位于单独的一行。
     28 //
     29 // [样例输入]
     30 // 1 10
     31 // 100 200
     32 // 201 210
     33 // 900 1000
     34 //
     35 // [样例输出]
     36 // 1 10 20
     37 // 100 200 125
     38 // 201 210 89
     39 // 900 1000 174
     40 //
     41 // [解题方法]
     42 // 计算每个数的循环节长度,求给定区间的最大值。
     43 //
     44 // 需要注意:
     45 // 1. 中间计算过程会超过 int 或 long (如果 int 或 long 型均为 4 字节存储空间) 型数据所能
     46 //    表示的范围,故需要选择 long long (8 字节存储空间)型整数(除非你使用的算法在做乘的时候不
     47 //    使用一般的乘法,而是使用替代方法实现原数的三倍加一)。
     48 // 2. 输入时可能较大的数在前面,需要调整顺序,这个是导致算法正确却 WA 的重要原因。
     49 // 3. 采用填表的方法保存既往计算结果,可以显著减少计算时间。
     50 //
     51 // 从网络上看了许多别人的解题方案,大多数都是忽略了第一点,求循环节长度的过程中,选择了 int 或
     52 // long (按 32 位 CPU 来假定,4 字节存储空间)类型的数据,当计算 (n * 3 + 1) 时会超出 32
     53 // 位整数的表示范围而得到错误答案,只不过 Programming Challenges 和 UVa 上的测试数据不是很强,
     54 // 所以尽管不完善但都会获得 AC。在 1 - 999999 之间共有 41 个数在中间计算过程中会得到大于 32 位
     55 // 无符号整数表示范围的整数,当测试数据包含这些数时,选用 int 或 long 类型有可能会得到错误的答案。
     56 //
     57 // 在中间计算过程中会超过 32 位整数表示范围的整数(括号内为循环节长度):
     58 // 159487(184)  270271(407)  318975(185)  376831(330)  419839(162)
     59 // 420351(242)  459759(214)  626331(509)  655359(292)  656415(292)
     60 // 665215(442)  687871(380)  704511(243)  704623(504)  717695(181)
     61 // 730559(380)  736447(194)  747291(248)  753663(331)  763675(318)
     62 // 780391(331)  807407(176)  822139(344)  829087(194)  833775(357)
     63 // 839679(163)  840703(243)  847871(326)  859135(313)  901119(251)
     64 // 906175(445)  917161(383)  920559(308)  937599(339)  944639(158)
     65 // 945791(238)  974079(383)  975015(321)  983039(290)  984623(290)
     66 // 997823(440)
     67     
     68 #include <iostream>
     69     
     70 using namespace std;
     71 
     72 #define min(a, b) ((a) <= (b) ? (a) : (b))
     73 #define max(a, b) ((a) >= (b) ? (a) : (b))
     74 
     75 #define MAXSIZE 1000000
     76     
     77 int cache[MAXSIZE];
     78 
     79 // 计算循环节长度。
     80 int counter(long long number)
     81 {
     82     if (number == 1)
     83         return 1;
     84     
     85     // 模 2 计算可用与计算代替,除 2 计算可用右移计算代替。
     86     if (number & 1)
     87         number += (number << 1) + 1;
     88     else
     89         number >>= 1;
     90     
     91     // 若 number 在缓存范围内则根据情况取用。
     92     if (number < MAXSIZE )
     93     {
     94         if (!cache[number])
     95             cache[number] = counter(number);
     96         return 1 + cache[number];
     97     }
     98     
     99     return 1 + counter(number);
    100 }
    101     
    102 int main(int ac, char *av[])
    103 {
    104     // 对于 GUN C++ 编译器,使用默认参数,在编译时会自动将全局数组 cache 中未初始化
    105     // 的元素初始化为 0,故可以不需要显式的进行初始化的工作。对于其他编译器应该根据情况调整。
    106     //
    107     // memset(cache, 0, sizeof(cache));
    108     //
    109     int first, second, start, end;
    110 
    111     while (cin >> first >> second)
    112     {
    113         // 得到给定范围的上下界。
    114         start = min(first, second);
    115         end = max(first, second);
    116         
    117         // 查找最大步长值。
    118         int result = 0, steps;
    119         for (int i = start; i <= end; i++)
    120             if ((steps = counter(i)) > result)
    121                 result = steps;
    122 
    123         // 输出。
    124         cout << first << " " << second << " " << result << endl;
    125     }
    126     
    127     return 0;
    128 }
    View Code

    来自csdn博客,作者寂静山林,链接:http://blog.csdn.net/metaphysis/article/details/6431937

  • 相关阅读:
    设计模式(四)——代理、模板、命令、访问者、迭代器、观察者
    设计模式(三)——桥接、装饰、组合、外观、享元
    设计模式(二)——工厂、原型、建造者、适配器
    设计模式(一)——设计原则、单例
    MySQL索引原理和锁
    MySQL(四)——索引使用等
    【摘】1范数与2范数优缺
    随机森林相关
    一些SEED数据集介绍
    神经网络的非线性
  • 原文地址:https://www.cnblogs.com/huashanqingzhu/p/4045115.html
Copyright © 2020-2023  润新知