【蓝桥杯】母牛的故事

题目描述

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

输入格式

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

输出格式

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

样例输入

2
4
5
0

样例输出

2
4
6

求解代码

我的代码

#include <iostream>
using namespace std;
typedef long long ll;
ll cownum(ll year,ll n,ll m){
	ll sum=0;
	if(year<=4){//当年份小于等于4时,小母牛数量就等于年份-1
		m+=year-1;
	}else{//大于4时,用year-4递归求母牛的数量。
          //在每次递归中会返回每次递归的母牛总数量,包括了母牛和小母牛。
          //要注意的时,递归一次n就要+4,因为年份-4,即新增了4头小母牛
		n+=cownum(year-4,n,m)+4;
	}
	sum=n+m;//总数的母牛n+小母牛m
	return sum;
}
int main()
{
  ll year;
  cin>>year;
  long long int count=0;//计数 
  while(year){
  	count=cownum(year,1,0);
  	cout<<count<<endl; 
  	cin>>year;
  }
  return 0;
}

使用递归实现,计算第n年共有多少头母牛时调用函数 cownum()。若年份小于等于4,则累加每一年产生的小母牛数量;否则递归计算前四年的母牛和小母牛数量,然后再加上第n-4年至第n年产生的所有母牛和小母牛的数量。

缺点:这种算法的时间复杂度为指数级,当 n 很大时计算时间会非常长。

优化代码(动态规划)

#include<iostream>
using namespace std;
  
long long cow[56] = {0,1,2,3,4}; // 在main函数外定义的数组会全部自动初始化为0
  
long long fab(int month) {
    if(cow[month] == 0) { // 没有算过的月份,数组内存的是0
        cow[month] = fab(month-1) + fab(month-3);
        return cow[month];
    } else {
        return cow[month];
    }
}
  
int main () {
    int n;
    while(scanf("%d", &n) && n) cout << fab(n) << endl;
    return 0;
}

使用动态规划实现,在 main() 函数外定义一个数组 cow 用来存储第1年到第55年每一年的母牛数量。由于第i年的母牛数量只与第 i-1 年和第 i-3 年的母牛数量有关,因此可以通过递推计算出所有需要的年份的母牛数量。

优点:这种算法的时间复杂度为线性级,计算速度更快。

对比

1.我的代码使用了递归算法,而第二个代码使用了动态规划算法。

2.我的代码没有对数组进行预处理,而是在递归计算中对每一年的母牛和小母牛数量进行了很多次重复计算;而第二个代码在 main() 函数外预处理了所有年份的母牛数量,避免了重复计算。

3.第一个代码使用了typedef定义long long为ll,方便在代码中多次使用;第二个代码直接使用了long long类型。

根据题目要求,两个代码在计算时都能得到正确的结果,但在时间效率和代码实现复杂度上有所不同。

递推求解

递推求解是利用第i年母牛的数量只与第i-1年和第i-3年的母牛的数量有关

故可以直接用递推求解

#include<iostream>
using namespace std;
  
int main () {
    int cow[56] = {0,1,2,3,4};
    for(int i = 4; i < 55; i ++) cow[i] = cow[i-1] + cow[i-3];
    int n;
    while(scanf("%d", &n) && n) cout << cow[n] << endl;
    return 0;
}

ChatGPT对“第i年母牛的数量只与第i-1年和第i-3年的母牛的数量有关”的解释是这样的:

根据题目描述,每一头小母牛从第四年开始每年都能生出一头小母牛,因此四年后的某一时刻,我们需要计算所有小母牛的数量,也就是第i年的母牛数量。

在第i-3年时,由于之前的所有小母牛都已经成熟了,可以生出新的小母牛。假设第i-3年有x头母牛,它们分别在第i-1年、第i年和第i+1年分别生下y1、y2、y3头小母牛,则第i年的母牛数量为x+y1,第i+1年的母牛数量为x+y1+y2,第i+2年的母牛数量为x+y1+y2+y3。

以上推导可以用一个方程表示:第i年的母牛数量 = 第i-1年的母牛数量 + 第i-3年的母牛能生的小母牛数量。由此可知,第i年的母牛数量只与第i-1年和第i-3年的母牛数量有关系,而与i-2年以及i-4年及更早的时间无关。

基于上述推论,我们可以运用动态规划算法来解决这个问题,避免使用递归算法需要进行很多次的重复计算,提高程序效率。

 大佬链接:https://blog.dotcpp.com/a/79100

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

会C++的Mr.Li

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值