南邮ACM 1010 数的计算 JAVA解法

数的计算

时间限制(普通/Java):1000MS/3000MS          运行内存限制:65536KByte
总提交:1033            测试通过:307

描述

要求找出具有下列性质数的个数(包含输入的自然数n):
先输入一个自然数n(n<=1000),然后对此自然数按照如下方法进行处理:
1. 不作任何处理;
2. 在它的左边加上一个自然数,但该自然数不能超过原数的一半;
3. 加上数后,继续按此规则进行处理,直到不能再加自然数为止.

输入

一个自然数n

输出

一个数,表示满足条件的数的个数

样例输入

6

样例输出

6

提示

样例说明:满足条件的数是6,16,26,126,36,136

题目来源

NOIP2001 普及组


主函数:

private static int s=0;
	private static final int MAX=1002;
	public static void main(String[] args) {
		Scanner sc=new Scanner(System.in);
		int n=sc.nextInt();
		fun2(n);
		//System.out.println(s+1);

	}


第一种方法:

本题难度看似不大,但如果用递归来做的话耗时非常大,因为需要重复计算的数据量太大了。当然我们也可以采取一边递归一边储存的方法,但计算量也还是不小,再进一步思考,实际上就是可以用如下的递推法来做;

private static void fun(int n) {
		for(int i=1;i<=n/2;i++){
			fun(i);
			s++;
		}
	}



第二种方法:

  2. 例如要求f(6),经过分析,我们知道:f(6)=f(1)+f(2)+f(3)+1,也就是说,f(6)的答案数量是在它之前可以取的所有自然数的答案数量之和(6之前可以取1,2,3三个自然数),最后加1是指数字6本身也是一个答案;
    3. 所以,我们可以知道f(n)=f(1)+f(2)+......f(trunc(n/2))+1;
    4. 因此,要求f(n),我们只需用上述公式编一个递推过程,把f(2)到f(n)全部求出即可,对于f(1000)也不超过1秒就能得到结果。

private static void fun1(int n) {
		int[] arr=new int[MAX];
		arr[1]=1;
		for(int i=2;i<=n;i++){
			for(int j=1;j<=i/2;j++){
				arr[i]+=arr[j];
			}
			arr[i]+=1;
		}
		System.out.println(arr[n]);
	}

第三种方法:

1. 对于f(7)=f(6)是显而易见的,也即f(2n+1)=f(2n)。那么,f(8)和f(7)之间有什么关系呢?
    2. 分析可知:f(8)和f(7)的差别是,f(8)除了包含f(7)的所有情况外,还要多加上f(4),即:f(8)=f(7)+f(4)。因此可得:f(2n)=f(2n-1)+f(n)。只需据此编一个递归小过程或者用递推方法即可。

private static void fun2(int n) {
		int[] arr=new int[MAX];
		arr[1]=1;
		for(int i=2;i<=n;i=i+2){
			arr[i]=arr[i-1]+arr[i/2];
			arr[i+1]=arr[i];
		}
		System.out.println(arr[n]);
	}

理论来源:感谢 http://www.it8g.com/RuanJian/200810/2001.htm

你可能感兴趣的:(java,递归,ACM,递推)