题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1032
有问题可以评论区留言。
这道题网上很多AC代码都是直接暴力求解的,即对于输入的m、n,单独计算每一个m、n之间(including m&n)的整数的cycle-length;输出cycle-length中最大者。这种暴力求解的方法在HDOJ上也能过,但是我认为这是因为HDOJ数据太弱,而非方法合理。
对于这道题,还是要稍微优化一下算法,打个表求解。大体思路就是:建立一个名称为 res 的数组,对于 n,res[n]即为n的cycle-length;初始化时先将res[1] = 1,其他的res[i] = 0;然后开始计算。
对于数字i,循环初始化:tempN = i;计算过程中,每次循环都探测一下res[tempN],如果res[tempN] != 0,则说明之前已经计算过tempN这个数的cycle-length,则 i 的cycle-length就是计算到tempN之前经历的循环次数cnt 与 res[tempN]之和,即res[i] = res[tempN] + cnt(祥见代码)。由此可减小计算量。
另外,这道题比较坑的地方就是,输入的m与n大小关系不确定,因而需要先做一下判断;大部分人的代码思路都是:当m>n时,交换m、n的值;但是在这种情况下,最后格式化输出的m、n对应的其实是输入时的n、m,因而会WA。
另外,这道题其实不能用32-bit整型计算,因为在计算113383的cycle-length时,会overflow,因而采用long long。
AC代码如下:
#include<iostream>
#define MAX 1000000
typedef long long LL;
LL res[MAX];
using namespace std;
void init()
{
for (int i = 0; i < MAX; i++)
res[i] = 0;
res[1] = 1;
}
int main()
{
LL m, n, temp, maxi, cnt, tempN;
init();
while (cin >> m >> n)
{
printf("%lld %lld ", m, n);
if (m > n)
{
temp = m;
m = n;
n = temp;
}
maxi = 1;
for (LL i = m; i <= n; i++)
{
cnt = 0, tempN = i;
while (true)
{
if (tempN < MAX && res[tempN])
{
res[i] = cnt + res[tempN];
break;
}
if (tempN%2 != 0)
tempN = 3*tempN +1;
else
tempN = tempN/2;
cnt++;
// printf("n = %lld, cnt = %lld\n", tempN, cnt);
}
if (res[i] > maxi)
maxi = res[i];
// printf("i = %d, maxi = %d\n", i, maxi);
}
cout << maxi << endl;
}
return 0;
}