P1464 Function——递归、记忆化搜索
题目描述
对于一个递归函数 \(w(a,b,c)\)
- 如果 \(a \le 0\) 或 \(b \le 0\) 或 \(c \le 0\) 就返回值 \(1\)。
- 如果 \(a>20\) 或 \(b>20\) 或 \(c>20\) 就返回 \(w(20,20,20)\)
- 如果 \(a<b\) 并且 \(b<c\) 就返回 \(w(a,b,c-1)+w(a,b-1,c-1)-w(a,b-1,c)\)。
- 其它的情况就返回 \(w(a-1,b,c)+w(a-1,b-1,c)+w(a-1,b,c-1)-w(a-1,b-1,c-1)\)
这是个简单的递归函数,但实现起来可能会有些问题。当 \(a,b,c\) 均为 \(15\) 时,调用的次数将非常的多。你要想个办法才行。
注意:例如 \(w(30,-1,0)\) 又满足条件 \(1\) 又满足条件 \(2\),请按照最上面的条件来算,答案为 \(1\)。
输入格式
会有若干行。
并以 \(-1,-1,-1\) 结束。
输出格式
输出若干行,每一行格式:
w(a, b, c) = ans
注意空格。
输入输出样例 #1
输入 #1
1 1 1
2 2 2
-1 -1 -1
输出 #1
w(1, 1, 1) = 2
w(2, 2, 2) = 4
说明/提示
数据规模与约定
保证输入的数在 \([-9223372036854775808,9223372036854775807]\) 之间,并且是整数。
保证不包括 \(-1, -1, -1\) 的输入行数 \(T\) 满足 \(1 \leq T \leq 10 ^ 5\)。
题解
#include <cstdio>
// 定义长整型别名,方便后续使用
#define LL long long
// 三维数组 dp 用于记忆化搜索,存储已经计算过的 w(a, b, c) 的结果
// 大小为 25 * 25 * 25 是为了能覆盖可能出现的 0 到 20 的 a、b、c 值
LL dp[25][25][25];
// 递归函数 w,用于计算 w(a, b, c) 的值
LL w(LL a, LL b, LL c)
{
// 情况 1:如果 a、b、c 中任意一个小于等于 0,根据题目规则,直接返回 1
if(a <= 0 || b <= 0 || c <= 0) return 1;
// 情况 2:如果 a、b、c 中任意一个大于 20,根据题目规则,将其转换为计算 w(20, 20, 20)
if(a > 20 || b > 20 || c > 20) return w(20, 20, 20);
// 情况 3:当 a < b 且 b < c 时
if(a < b && b < c)
{
// 检查 dp[a][b][c - 1] 是否已经计算过,如果没有计算过(值为 0)
if(dp[a][b][c - 1] == 0)
{
// 递归调用 w 函数计算 w(a, b, c - 1) 的值,并将结果存储到 dp[a][b][c - 1] 中
dp[a][b][c - 1] = w(a, b, c - 1);
}
// 检查 dp[a][b - 1][c - 1] 是否已经计算过,如果没有计算过(值为 0)
if(dp[a][b - 1][c - 1] == 0)
{
// 递归调用 w 函数计算 w(a, b - 1, c - 1) 的值,并将结果存储到 dp[a][b - 1][c - 1] 中
dp[a][b - 1][c - 1] = w(a, b - 1, c - 1);
}
// 检查 dp[a][b - 1][c] 是否已经计算过,如果没有计算过(值为 0)
if(dp[a][b - 1][c] == 0)
{
// 递归调用 w 函数计算 w(a, b - 1, c) 的值,并将结果存储到 dp[a][b - 1][c] 中
dp[a][b - 1][c] = w(a, b - 1, c);
}
// 根据题目规则,当 a < b 且 b < c 时,w(a, b, c) 的值等于 w(a, b, c - 1) + w(a, b - 1, c - 1) - w(a, b - 1, c)
// 由于前面已经确保所需的中间结果都已计算并存储在 dp 数组中,直接从 dp 数组中取值进行计算
dp[a][b][c] = dp[a][b][c - 1] + dp[a][b - 1][c - 1] - dp[a][b - 1][c];
}
// 情况 4:当不满足 a < b 且 b < c 时
else
{
// 检查 dp[a - 1][b][c] 是否已经计算过,如果没有计算过(值为 0)
if(dp[a - 1][b][c] == 0)
{
// 递归调用 w 函数计算 w(a - 1, b, c) 的值,并将结果存储到 dp[a - 1][b][c] 中
dp[a - 1][b][c] = w(a - 1, b, c);
}
// 检查 dp[a - 1][b - 1][c] 是否已经计算过,如果没有计算过(值为 0)
if(dp[a - 1][b - 1][c] == 0)
{
// 递归调用 w 函数计算 w(a - 1, b - 1, c) 的值,并将结果存储到 dp[a - 1][b - 1][c] 中
dp[a - 1][b - 1][c] = w(a - 1, b - 1, c);
}
// 检查 dp[a - 1][b][c - 1] 是否已经计算过,如果没有计算过(值为 0)
if(dp[a - 1][b][c - 1] == 0)
{
// 递归调用 w 函数计算 w(a - 1, b, c - 1) 的值,并将结果存储到 dp[a - 1][b][c - 1] 中
dp[a - 1][b][c - 1] = w(a - 1, b, c - 1);
}
// 检查 dp[a - 1][b - 1][c - 1] 是否已经计算过,如果没有计算过(值为 0)
if(dp[a - 1][b - 1][c - 1] == 0)
{
// 递归调用 w 函数计算 w(a - 1, b - 1, c - 1) 的值,并将结果存储到 dp[a - 1][b - 1][c - 1] 中
dp[a - 1][b - 1][c - 1] = w(a - 1, b - 1, c - 1);
}
// 根据题目规则,当不满足 a < b 且 b < c 时,w(a, b, c) 的值等于 w(a - 1, b, c) + w(a - 1, b, c - 1) + w(a - 1, b - 1, c) - w(a - 1, b - 1, c - 1)
// 由于前面已经确保所需的中间结果都已计算并存储在 dp 数组中,直接从 dp 数组中取值进行计算
dp[a][b][c] = dp[a - 1][b][c] + dp[a - 1][b][c - 1] + dp[a - 1][b - 1][c] - dp[a - 1][b - 1][c - 1];
}
// 返回计算得到的 w(a, b, c) 的值
return dp[a][b][c];
}
int main()
{
LL a, b, c;
// 无限循环读取输入的 a、b、c
while(scanf("%lld%lld%lld", &a, &b, &c))
{
// 当输入为 -1 -1 -1 时,结束程序
if(a == -1 && b == -1 && c == -1) return 0;
// 输出提示信息
printf("w(%lld, %lld, %lld) = ", a, b, c);
// 调用 w 函数计算 w(a, b, c) 的值并输出结果
printf("%lld\n", w(a, b, c));
}
}
浙公网安备 33010602011771号