[递归]母牛的故事—算法例题

(完整代码在最下面)

题目描述:

有一头母牛,它每年年初生一头小母牛。每头小母牛从第四个年头开始,每年年初也生一头小母牛。请编程实现在第n年的时候,共有多少头母牛?

输入:

输入数据由多个测试实例组成,每个测试实例占一行,包括一个整数n(0<n<55),n的含义如题目中描述。n=0表示输入数据的结束,不做处理。

输出:

对于每个测试实例,输出在第n年的时候母牛的数量。
每个输出占一行。

样例输入:

2 4 5 0

样例输出:

2 4 6


首先看到题目已经明确了用递归(回溯)算法来做,当然用其他的也可以,根据题目描述理解,大概是开始只有一头母牛,然后每年都会以题中的规则增长母牛,求到最后牛总个数

增长规则:一头母球每年初生一头母牛,小母牛第四年初生一头母牛。

解题思路:

sum(n):第n年母牛的总数

year(n):第n年

1. 首先,按照我的思路是把题完全看了一遍,刚开始看到最后的输入输出还不理解什么意思,后来知道每个数代表经历多少年,以0结束,输出结果是对应年的母牛总数————以题中为例:

2 4 5 0 就是year(2),year(4),year(5),0代表此次输入结束

2 4 6 代表sum(2),sum(4)和sum(5)

2. 设计递归函数代码

我们已经知道母牛的增长规则了,包含了几种情况

①year == 1

②year > 1

        1)year <= 4

        2)year > 4

为什么会有这几种情况,首先递归的一个基本思想先分类:把最简单(这里是year == 1)的情况分一类,把其他情况分一类(可能还需要继续细分,这里需要自己的经验判断了)。

然后我在纸上计算出了 sum(n) 其实不包括第n年出生的牛,而且从第4年开始每年就有小母牛会生崽,所以分为第四年前和第4年后的情况

下面开始编写代码:

①输入规则

我们已经知道了是循环输入的,直到0结束,所以输入的代码肯定要用循环来做而且sum(n)记录在数组或集合中

List<Integer> a = new ArrayList<Integer>();
Scanner scanner = new Scanner(System.in);
int year,sum = 0;
//year是获取输入的年——判断输入的年是否满足条件
//sum是年份对应的母牛个数
while(!(year =  scanner.nextInt()) <= 0)){
sum = recursion(year);
a.add(sum);
}

小伙伴们应该可以看明白,如果year > 0就进入循环调用递归函数,之后把返回的sum结果添加到list集合中,搞定!

②递归实现

上面已经罗列了几种可能的情况,直接上代码

public static int recursion(int year){
if(year == 1 || year == 0){
return 1;
}else{
if(year <= 4){
return recursion(year - 1) + 1;
}else{
return recursion(year - 1) + recursion(year - 3);
}
}
}

其他代码不说,我们来分析分析进入else以后

① if ( year <=4 && year > 1 ) 这一年刚好没有小母牛生崽,所以直接调用recursion(year - 1) + 1,函数内的 - 1是要递归计算这几年所有出生的小母牛,总体加1是因为每年初母牛会生一个小母牛

② if ( year > 4 ) ,要考虑小母牛生崽的情况了,其实也不难,我们把刚开始的母牛递归,加上出生大于四年之后的小母牛递归情况,就把所有的母牛都考虑进来了。

    1) 为什么递归小母牛要传入year - 3?

因为我们计算n年来出生的总数量,其实是不把第n年出生的小母牛计算在内的,所以计算的是n - 1年的母牛总和,所以year 减的是3而不是4。

    2)为什么year > 4 的返回值不是 + 1 ?

+1原本就是为了表示这年比上年多生一个小母牛,这个有点难理解,可以理解为递归某一次recursion(n) + recursion(n-3)的时候会返回上一次递归母牛所有的数量(不包括递归小母牛的数量,但包括这年生的一个小母牛),所以就抵消了那个+1,也就是说两个递归的返回值已经包含了这年新生的小母牛了,所以把外面的+1去掉了,画思路图验证一下

 

我们要仔细想一下,递归母牛是为了计算母牛出生的崽子,那递归出生年>4的小母牛不也是计算小母牛出生的崽子嘛,好多小伙伴没想到小母牛也需要递归一下,这就导致了思路断片。

import java.util.Scanner;
import java.util.*;
public class Main {
public static void main(String[] args) {
List<Integer> a = new ArrayList<Integer>();
Scanner scanner = new Scanner(System.in);
int year,sum = 0;
while(!((year =  scanner.nextInt())<= 0)){
sum = recursion(year);
a.add(sum);
}
for(Integer x : a){
System.out.println(x);
}
}
public static int recursion(int year){
if(year == 1 || year == 0){
return 1;
}else{
if(year <= 4){
return recursion(year - 1) + 1;
}else{
return recursion(year - 1) + recursion(year - 3);
}
}
}
}

验证此算法是否正确的地址如下  →  母牛的故事

有问题欢迎在下方留言,侵删!

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值