UVa系列——100/The 3n + 1 problem

引用请注明出处:http://blog.csdn.net/int64ago/article/details/7413434

本题注意两个方面:

1、虽然题目给的范围是1~1000000,其实计算的过程中的中间值有的是很大的,所以要用unsigned long long

2、不重复计算,我同时用了两种方案,一种是计算的过程中判断是否遇到已经计算过的,另一种是计算的过程中把“有意义”的中间值存了起来,然后得到结果的时候顺便回溯处理了,事实证明两种一起用效率还不错,44ms过了


#include  <stdio.h>
#include  <stdlib.h>
#define  MAX_NUM 1000000

int cyc_num[MAX_NUM + 1]={0};
int back_cyc_num[MAX_NUM+1];
int back_len;


/* 处理连带计算出来的cyc_num[] */
void pro_back(int ret_num)
{
	int i;
	for(i = 0; i != back_len; ++i){
		cyc_num[back_cyc_num[i]] = ret_num + back_len - i;
	}
	
}


/*
 * 计算cyc_num[num]的值
 * 如果计算过程中遇到已经计算过得cyc_num[]
 * 则不重复计算
 */
int do_creat_cyc(unsigned long long num)
{
	int cnt = 1;
	back_len = 0;
	while(num != 1){
		if(num % 2 == 0){
			num /= 2;
		} else{
			num = num * 3 + 1;
		}
		if(num <= MAX_NUM && cyc_num[num]){
			pro_back(cyc_num[num]);
			return cnt + cyc_num[num];
		}
		back_cyc_num[back_len++] = num > MAX_NUM ? 0:num;	
		++cnt;
	}
	return cnt;
}


/* 
 * 计算1~1000000之间所有的cyc_num[]值
 * 如果已经计算过则跳过
 */
void creat_cyc(void)
{
	int i;
	for(i = 1; i <= MAX_NUM; ++i){
		if(cyc_num[i]){
			continue;
		} else{
			cyc_num[i] = do_creat_cyc(i);
		}
	}
	
}


void let_small_big(int *const x, int *const y)
{
	int tmp = *x;
	*x = *y;
	*y = tmp;
}

int get_max(int beg, int end)
{
	int mmax = 0;
	int i;
	if(beg > end){
		let_small_big(&beg, &end);
	}
	for(i = beg; i <= end; ++i){
		if(mmax < cyc_num[i]){
			mmax = cyc_num[i];
		}
	}
	return mmax;	
}



int main(int argc, char *argv[])
{
	int beg, end;
	creat_cyc();
	while(scanf("%d%d", &beg, &end) != EOF){
		printf("%d %d %d\n", beg, end, get_max(beg, end));
	}
	return 0;
}

你可能感兴趣的:(UVa系列——100/The 3n + 1 problem)