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));
}
}
发布于   xiins  阅读(5)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
点击右上角即可分享
微信分享提示