卡拉兹(Callatz)猜想:
对任何一个正整数 n,如果它是偶数,那么把它砍掉一半;如果它是奇数,那么把 (3n+1) 砍掉一半。这样一直反复砍下去,最后一定在某一步得到 n=1。卡拉兹在 1950 年的世界数学家大会上公布了这个猜想,传说当时耶鲁大学师生齐动员,拼命想证明这个貌似很傻很天真的命题,结果闹得学生们无心学业,一心只证 (3n+1),以至于有人说这是一个阴谋,卡拉兹是在蓄意延缓美国数学界教学与科研的进展……
我们今天的题目不是证明卡拉兹猜想,而是对给定的任一不超过 1000 的正整数 n,简单地数一下,需要多少步(砍几下)才能得到 n=1?
输入格式:
每个测试输入包含 1 个测试用例,即给出正整数 n 的值。
输出格式:
输出从 n 计算到 1 需要的步数。
输入样例:
3
输出样例:
5
思考:
这种题就是奇偶判断进行相应的处理并计数,其中关键是奇偶判断处理和时间开销问题。
- 奇偶处理:对于一个数值 n 其奇偶性,是用 n%2 进行处理,还是 n&1 来处理;
取模运算(%):其本质在计算机中还是用二进制数值的“原码除法”,而“原码除法”本质是“原码加法”和“原码减法”,进行多次二进制运算,详细计算过程及原因《计算机组成原理》有讲;
与运算(&):本质也是二进制运算,但它直接取二进制原码(负数用补码比较)的最后一位和1相与,相同为1,不同为0,只进行一次二进制运算,当然比取模运算快多了(快的飞起)。为什么这样果断?想想看,奇数的二进制码最后一位是不是都是1,偶数的二进制码最后一位都是0!!!
(可参考本人另一篇博客讲解:https://blog.youkuaiyun.com/C_DreShadow/article/details/83758222)- 时间开销:除号(/)和移位符号(>>)之间的关系,其中二进制码除法的计算过程不在多说,上面解释有。主要是移位运算,其实就是二进制码整体相右平移移位,你说那个快点,当然是移位运算啦。
代码:
// PAT_code_test.cpp: 定义控制台应用程序的入口点。 // #include <iostream> #include <stdio.h> using namespace std; int main() { int n; cin >> n; int num = 0; while (true) { if (n == 1)break; if (n & 1) // &与运算 直接判断数字最后一个二进制位是否为1 { n = (3 * n + 1) >> 1; } else { n = n >> 1; // >>移位运算 直接将数字的二进制码整体右移移位,高位用0补齐 } ++num; } cout << num << endl; return 0; }