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)); } }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了