ACM 3n+1问题

[问题描述]*考虑如下的序列生成算法:

从整数 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

[解决思路]
 
version 1
 
1 首先考虑概念循环节,它指的是一个数生成的数字序列长度,以1为终止条件
2 最终要输出的是所给数字区间内,循环节最大的数字。
3 每个数字对应的循环节长度存储在数组中,区间内的各个数字作为数组下标
注意:
1 1也计算在循环节长度内
2 题目要求的2个输入数字,不见得左边数字就小于右边数字
代码如下:
#include <stdio.h>

int longestNum(int begin,int end)
{
    if(begin>end)
    {
        begin=begin^end;
        end=begin^end;
        begin=begin^end;
    }
    int maxFunct(int [],int ,int);
	//vc6并未支持到c99,
	//c99支持在初始化数组时以变量为下标
	//在函数体内初始化数组时,未赋值,默认不是0,
	// 起止点区间内的循环节长度计数,其中 0-begin之间的数组浪费掉了
	/** 事实上,我们要的是最大值,只要后一个数比前一个数大,丢掉前一个数就行了,不必每个都记忆
	比较放在主函数中*/
	int count[end+1];
	int i;
	for(i=0;i<end+1;++i)
    	{
     	   count[i]=1;
  	}
    // /2或3n+1的承担者
	int num;
	//最大值
	int max=0;
	//c89不支持在for()中定义变量
	// 在setting->compiler...->other option中添加“-std=c99”不含引号
	int j;
	for(j=begin;j<=end;++j)
	{
		num=j;
		while(num!=1)
		{
			if(num%2==0)
				num=num/2;
			else
				num=num*3+1;
			count[j]++;
		}
//		printf("%d,",count[i]);
	}
	max=maxFunct(count,begin,end);
	return max;
}

int maxFunct(int arr[],int begin,int end)
{
    int max=arr[begin];
    int j;
    for( j=begin;j<=end;++j)
	{
		if(max<arr[j])
			max=arr[j];
	}
    return max;
}	
version 1 经验:
 
1 c99支持了for循环()内定义变量
 

2 codeblock下,在setting->compiler...->other option中添加“-std=c99”不含引号,支持c99编译

3 在函数体内定义数组时,如果没有赋初值,那么系统默认的并不是该数组所存元素的默认值,而是一个不确定的值。

4 while(scanf("%d%d",&begin,&end)!=EOF)
 
5当if else在执行完各自对应的语句后,都需要执行某些语句B时,将B放在if else后
 
再思考
 
1 事实上,在version1 中,数组是必要的吗?
 
1.1 在0到begin下标对应的数组元素并未使用,空间浪费
1.2 题给要求是输出最大的循环节数,并不需要保留其他数字对应的循环节数,在比较大小的过程中,得到一个大的数后,小的丢掉即可。
 
综上,并不需要在本题中设置数组。代码重构如下:
 
version 2
 
#include <stdio.h>

int cyclePoint(int num)
{
    int count=1;

    while(num!=1)
    {
        if(num%2==0)
            num=num/2;
        else
            num=num*3+1;
        count++;
    }
	return count;
}

int maxFunct(int begin,int end)
{
    int max=0;
    if(begin>end)
    {
        begin=begin^end;
        end=begin^end;
        begin=begin^end;
    }
    for(int i=begin;i<=end;++i)
	{
		if(max<cyclePoint(i))
			max=cyclePoint(i);
	}
    return max;
}

 
 
  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值