3n+1_problem_Uva

这道题,其实说难也难,说简单也简单,关键在其测试数据。如果测试数据很苛刻,就很难了(参看博客UVa Problem 100 The 3n+1 problem (3n+1 问题))。

这里,我要写两点想法:第一,题目中说求数字i,j之间的最大循环节长度,但是样例输入却都是按min,max的顺序给出,这让我们产生了一种错觉:输入就是按较小数、较大数输入的,这也是我多次TL的原因。记住:当题目要求模棱两可的时候,一定要注意其真正的意思,不要带入自己的观念。第二,我列举了10以内数的循环节长度,发现相邻两个数中奇数较大时,奇数的循环节长度一般比偶数的大;但是如果偶数较大时,这个就不成立,因此,当一个范围的最大数是偶数的时候,要单独计算其循环节长度,剩下的就归结为前一类情况了,也就可以只计算奇数的循环节长度(这里是不严格的推广)。另外,一个范围(min到max)内的大数部分(从max/2到max部分的数)比小数部分(min到max/2)的最大循环节长度大。所以有了下面的程序:

#include<stdio.h>
int main()
{
	int min,max,min_o,max_o;
	int i,tmp,rst,count;
	char input[100];

	while(gets(input))/*处理循环输入*/
	{
		rst = 0;
		sscanf(input,"%d %d",&min_o,&max_o);
		if(max_o > min_o )
		{
			min = min_o;
			max = max_o;
		}
		else
		{
			max = min_o;
			min = max_o;
		}
		
		if(max%2 == 0)/*单独处理偶数最大上限,下面只判断奇数*/
		{
			count = 0;
			tmp = max;
			while(tmp != 1)/*处理最大数*/
			{
				if(tmp%2 == 0)
					tmp /= 2;
				else tmp = tmp*3 + 1;

				count ++;
			}
			if(count > rst)/*记录最大数*/
				rst = count;
		}

		tmp = max/2;/*范围的大数部分*/
		if(tmp%2 == 0)
			tmp ++;

		if(tmp < min)/*修正范围*/
		{
			if(min%2 == 0)
				tmp = min + 1;
			else tmp = min;
		}

		for(i = tmp;i <= max;i += 2)/*循环这个范围内的大数那部分*/
		{
			tmp = i;
			count = 0;
			while(tmp != 1)/*处理每一个数*/
			{
				if(tmp%2 == 0)
					tmp /= 2;
				else tmp = tmp*3 + 1;

				count ++;
			}
			if(count > rst)/*记录最大数*/
			{
				rst = count;
			}
		}
		printf("%d %d %d\n",min_o,max_o,rst + 1);/*按输入的顺序输出i,j*/
	}
	
	return 0;
}



你可能感兴趣的:(3n+1_problem_Uva)