考虑下列算法:
1. input n
2. print n
3. if n = 1 then STOP
4. if n is odd then n <- 3n+1
5. else n <- n/2
6. GOTO 2
输入:22,
打印序列:22 11 34 17 52 26 13 40 20 10 5 16 8 4 2 1
假设对于所有整数值,算法可终止(打印到1时),但不知道假设是否为真。对于所有的整数n,例如 0<n<1,000,000 是已验证的。
给定输入n,可能确定在打印到1时一共输出的数字的个数,该个数成为n的周期长度,对于上面的例子,22的周期长度为16.
对于任意两个数i,j,找到i,j之间的所有整数中,最大的周期长度。
输入是一系列整数对i,j,每行一对整数。所有整数n, 0<n<10,000 ,需要测试[i,j]内的所有整数,来确定最大的周期长度
对于每对输入整数i,j,需要输出i,j和[i,j]区间内的最大的周期长度。这三个数用至少一个空格分开,位于一行内。输出的i,j要和输入的顺序相同。
1 10
100 200
201 210
900 1000
1 10 20
100 200 125
201 210 89
900 1000 174
直接计算的话,由于数据计算量在10,000内,可以
打表的话,与直接计算只能节省重复区间的计算量,不会快很多
最快的算法是深度搜索+记忆优化(记忆优化相当于打表),适用于n为更大的数时,作为拓展了解一下吧。。。
注意:
1. 打印1本身也算在周期内
2. 每对数i,j不一定是i < j,需要格外留意,输出时要按照输入时的顺序输出
164K 16MS C 859B
#include <stdio.h>
int steps(n)
{
int count = 1;
while(n != 1)
{
if(n&1)//按位与运算,奇数的二进制末尾为1,奇数&1结果为1
{
//设 k = n/2, 则 3(2k+1)+1 = (3k+2)*2,减少一次迭代
n = n/2 * 3 + 2;
count += 2;
}
else
{
n /= 2;
++count;
}
}
return count;
}
int main()
{
int i,j,max,t,k,k_step;//t用于交换,k用于遍历
int tmp_i,tmp_j;//用于保存输入的i,j的顺序
while(scanf("%d%d",&i,&j)==2)
{
tmp_i = i;
tmp_j = j;
if(i>j){
t = i;
i = j;
j = t;
}
max = steps(i);
for(k = i+1; k <= j; ++k)
{
k_step = steps(k);
if(max < k_step)
max = k_step;
}
printf("%d %d %d\n", tmp_i,tmp_j,max);
}
return 0;
}
204K 0MS C 924B
#include <stdio.h>
int steps_arr[10001] = {0};//从1开始计数
void calcSteps()
{
int i,n;
for(i=1; i < 10001; ++i)
{
steps_arr[i] = 1;
n = i;
while(n!=1)
{
if(n&1){
n = n/2 * 3 + 2;
steps_arr[i] = steps_arr[i] + 2;
}
else
{
n /= 2;
steps_arr[i] = steps_arr[i] + 1;
}
}
}
}
int main()
{
int i,j,t,k,max;
int temp_i,temp_j;
calcSteps();
while(scanf("%d%d",&i,&j)==2)
{
temp_i = i;
temp_j = j;
if(i > j)
{
t = i;
i = j;
j = t;
}
max = steps_arr[i];
for(k = i+1; k <= j; ++k)
{
if(max < steps_arr[k])
max = steps_arr[k];
}
printf("%d %d %d\n",temp_i, temp_j, max);
}
return 0;
}
244K 0MS C 941B
#include <stdio.h>
int steps_arr[20001] = {0};
int dfs(int n)
{
if(n==1)
return 1;
if(n > 20000)
{
if(n&1)
return dfs(n/2 *3 + 2) + 2; //这里就是深度搜索,向下递归一层
else
return dfs(n/2) + 1;
}
if(!steps_arr[n]) //没有求过n的步数,则需要求(否则可以用上次返回的值【记忆】)
{
if(n&1)
return dfs(n/2 *3 + 2) + 2;
else
return dfs(n/2) + 1;
}
else
return steps_arr[n];
}
int main()
{
int i,j,max,k,t;
steps_arr[1] = 1;
for(i = 1; i < 10001; ++i)
{
steps_arr[i] = dfs(i);//打表,主要保存那些频繁计算的数的步数
}
while(scanf("%d%d",&i,&j)==2)
{
printf("%d %d ",i,j);
max = 0;
if(i > j)
{
t = i;
i = j;
j = t;
}
for(k = i; k <= j; ++k)
{
if(max < steps_arr[k])
max = steps_arr[k];
}
printf("%d\n", max);
}
return 0;
}