题目链接:http://soj.sysu.edu.cn/1029
题目大意:刚开始是有一对成年兔子,每对成年兔子在一个月后生下一对小兔子,小兔子经过 m 个月后成长为成年兔子。给定兔子从小兔子成长为成年兔子所需要的时间 m 个月,问在 d 个月后兔子的总对数。假设在整个过程中没有兔子死亡。
例如:当 m = 2, d = 3 时,输入结果为 5。但是这里我有个问题一直没想明白,按照题目的意思刚开始是1对兔子,那一个月后应该是1对成年兔子和1对小兔子(这对小兔子才刚出生),两个月后应该是一对成年兔子(还是最开始的那对成年兔子)和一对一月大的小兔子(由上个月出生成长起来的)和一对刚出生的小兔子,此时总共是3对兔子。3个月后就有2对成年兔子(一对是刚开始的成年兔子,一对是由一月后的一月大的兔子成长起来的),一对是一月大的兔子,还有一对是刚出生的兔子,总共是4对兔子。但是题目却不是这样理解的,它的理解方式应该是这样的:刚开始是一对成年兔子,1月后就有一对成年兔子和一对小兔子,总共是2对兔子;两个月后就有两对成年兔子(上个月的小兔子已经变成成年兔子了。是兔子出生就默认一个月大呢还是兔子经过1个月就能成长为成年兔子?我还是没想明白)和一对小兔子,总共是3对兔子;三个月后就有3对成年兔子和2对小兔子,总共是5对兔子。先不管这些,就按题目的意思来解题吧。
解题思路:递推(也可以说是动态规划) + 高精度加法
递推:假设兔子经过 m 个月从小兔子成长为成年兔子,用 dp[i] 表示第 i 个月后兔子的总对数,那么有 dp[i] = dp[i - 1] + dp[i - m]。其中边界条件为:for i from 0 to m: dp[i] = i + 1.
高精度加法:如果只是上述的简单的递推的话,那用一个int一维数组存储数据也就完事了,但是本题中出现大数据超出int范围,于是不得不考虑用高精度加法。那么现在一维数组不能满足需求了,考虑平时到高精度加法都是把字符串转换为int数组存储然后再操作,这里就直接使用二维数组 int a[][]来表示,其中a[i][]表示第 i 个月后兔子总对数k,k 的每一位存在a[i][]中。
#include <iostream>
using namespace std;
int main()
{
// 用二维数组存储每个数,i 个月后兔子总数存储在 a[i] 中
// a[i][j]表示 i 个月后兔子总数从右往左数第 110 - j 位的数字
int m, d, a[110][110];
while (1)
{
cin >> m >>d;
if (m == 0 && d == 0)
break;
// 初始化
for (int i = 0; i < 110; i++)
for (int j = 0; j < 110; j++)
a[i][j] = 0;
for (int i = 0; i <= m; i++)
a[i][109] = i + 1;
// 递推
for (int i = m + 1; i <= d; i++)
{
// 高精度加法
for (int j = 109; j >= 0; j--)
{
a[i][j] += a[i - 1][j] + a[i - m][j];
// 处理进位
if (a[i][j] > 9)
{
a[i][j - 1] += a[i][j] / 10;
a[i][j] %= 10;
}
}
}
// 输出结果,排除前面的 0
for (int i = 0; i < 110; i++)
if (a[d][i] != 0)
{
for (int j = i; j < 110; j++)
cout << a[d][j];
break;
}
cout << endl;
}
return 0;
}