题目1464

  1. #include<iostream>  
  2. #include<string>  
  3. #include<algorithm>  
  4. using namespace std;  
  5.   
  6. int main()  
  7. {  
  8.     freopen("in.in""r", stdin);  
  9.     freopen("out.out","w", stdout);  
  10.   
  11.     //输入部分  
  12.     char input[81];  
  13.     while(cin >> input)  
  14.     {  
  15.     string s = input;  
  16.     int len = s.length();  
  17.   
  18.     //计算部分  
  19.     int n1,n2, n3,i,j;  
  20.   
  21.     n1 = n3 =(len + 2) / 3 -1;  
  22.     n2 = len - n1 - n3;  
  23.     string left,right, bottom;  
  24.   
  25.     left = s.substr(0,n1);  
  26.     right = s.substr(len-n3,n3);  
  27.     bottom = s.substr(n1,n2);  
  28.     reverse(right.begin(),right.end());  
  29.     for (i=0; i<n1; i++)  
  30.     {  
  31.         cout << left[i];  
  32.         for (j=0; j<n2-2; j++)  
  33.             cout << " ";  
  34.         cout << right[i] << endl;  
  35.     }  
  36.     cout << bottom << endl;  
  37.     }  
  38.     return 0;  
  39. }  
<think>好的,我现在要帮用户解答洛谷P1464的问题,首先我得先确定用户的问题是什么。题目编号是P1464,但用户提到的是C语言,所以可能题目需要用C语言来解决。不过用户可能想了解题目的内容、解题思路或者具体的代码实现。 首先,我需要回忆一下洛谷P1464题目内容。洛谷的题目编号可能会更新,但根据记忆,P1464应该是一个关于函数递归调用的题目,可能与记忆化搜索或动态规划有关。题目的大意是给定一个递归函数w(a, b, c),并规定当a、b、c中任意一个小于等于0时返回1,当任何一个大于20时返回w(20,20,20)。其他情况下根据a、b、c的大小关系递归调用,并最终计算某个结果。但由于直接递归会导致大量的重复计算,导致超时,所以必须采用记忆化存储已计算的结果,避免重复计算。 接下来,我需要确认用户的需求。用户可能遇到了这个题目,需要知道如何用C语言实现,或者需要解题思路。他们可能已经尝试过直接递归,但发现效率不够,需要优化方法,比如记忆化。 首先,我应该先描述题目,确保用户和我在同一页上。题目通常给出具体的递归定义,用户需要根据这个定义实现函数,并处理输入输出。例如,输入多组测试数据,输出对应的w(a,b,c)的值,同时要注意题目中的条件,比如任何参数超过20则视为20,这样可以减少计算量。 然后,解题思路的关键点在于如何避免重复计算。直接递归会有指数级的时间复杂度,因为每次调用都会分解成多个子问题。这时候需要记忆化技术,即用一个三维数组来存储已经计算过的结果,下次需要时直接取出,避免重复计算。这在C语言中可以通过定义一个三维数组来实现,比如int memo[21][21][21],因为题目中参数超过20的会被处理成20,所以数组的大小是21x21x21。 接下来需要考虑如何实现这个记忆化。在每次计算w(a,b,c)之前,先检查memo[a][b][c]是否已经计算过,如果有就直接返回,否则按照递归定义计算,并将结果保存到memo中。需要注意的是,参数在处理前可能需要被截断到20,如果超过的话。例如,在进入函数前,先判断a、b、c是否大于20,如果是的话,统一处理为20,这样可以减少数组的维度和计算量。 然后,关于输入输出的处理。题目可能要求输入多组测试用例,直到输入三个-1为止。每次输入三个数a、b、c,输出w(a,b,c)的值。在C语言中,可以使用循环读取scanf的输入,直到满足终止条件。 现在,我需要考虑可能的错误点。例如,数组的初始化是否正确,递归的条件是否正确处理,特别是边界条件,比如a、b、c小于等于0的情况。此外,需要注意在存储到memo之前,是否已经将参数处理到0-20的范围,因为数组的索引不能是负数,而题目中当参数小于等于0时返回1,所以在处理参数时,如果参数<=0,可以直接返回1,不需要存储到memo中。或者,在进入函数时,先处理参数,将小于等于0的参数统一视为0或直接处理返回1。 可能的实现步骤: 1. 预处理参数:在计算w(a,b,c)之前,先将每个参数转换为不超过20的值。例如,如果a>20,则a=20;同样处理b和c。如果任何参数<=0,则直接返回1。 2. 记忆化数组的初始化:使用一个三维数组memo[21][21][21],初始值设为-1,表示未计算。每次计算前检查对应的位置是否为-1,如果不是,直接返回存储的值。 3. 递归函数的实现:按照题目给出的递归公式,分解各个情况,递归调用函数,并将结果保存到memo中。 4. 输入输出的处理:循环读取输入,直到遇到-1 -1 -1,每个输入处理后输出结果。 在C语言中,需要注意函数的递归调用可能会导致栈溢出,但由于记忆化的优化,递归深度会被限制,因为参数已经被限制在0-20之间,所以不会出现太深的递归。例如,当a、b、c都是20的时候,递归可能会分解为多个子调用,但由于记忆化,每个子问题只会计算一次,所以总的调用次数是有限的。 可能的代码结构: - 定义全局的三维数组memo。 - 实现递归函数w(a,b,c)。 - 主函数处理输入输出。 例如: ```c #include <stdio.h> #include <string.h> int memo[21][21][21]; int w(int a, int b, int c) { if (a <=0 || b <=0 || c <=0) return 1; if (a >20 || b >20 || c >20) return w(20,20,20); if (memo[a][b][c] != -1) return memo[a][b][c]; if (a < b && b < c) { memo[a][b][c] = w(a,b,c-1) + w(a,b-1,c-1) - w(a,b-1,c); } else { memo[a][b][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); } return memo[a][b][c]; } int main() { int a, b, c; memset(memo, -1, sizeof(memo)); // 初始化为-1 while (scanf("%d%d%d", &a, &b, &c) != EOF) { if (a == -1 && b == -1 && c == -1) break; printf("w(%d, %d, %d) = %d\n", a, b, c, w(a,b,c)); } return 0; } ``` 这里需要注意的是,在每次调用w函数之前,参数已经被处理成不超过20的值。例如,当a>20时,函数内部会调用w(20,20,20),而memo数组的大小正好是21x21x21,所以不会有数组越界的问题。 另外,初始化memo数组为-1,表示未被计算过。每次计算完一个结果后,存入memo中,这样下次遇到同样的参数时就可以直接取出结果。 测试的时候,例如题目中的样例输入,比如输入1 1 1,应该返回2;输入2 2 2,返回4;输入20 20 20,返回结果(具体数值可能根据递归公式而定)。 用户可能遇到的错误包括忘记处理参数超过20的情况,或者在递归条件中的判断顺序错误,导致数组越界或者错误的结果。另外,在记忆化数组的初始化时,必须确保所有可能用到的位置都被正确初始化,否则可能导致错误的值被读取。 最后,需要提醒用户,虽然递归在这里可行,但由于C语言的递归深度限制,如果参数没有被正确处理的话,可能会导致栈溢出。但在这个题目中,由于参数被限制在20以内,所以递归深度不会太大,可以安全使用。</think>### 洛谷 P1464 题解(C语言实现) #### **题目概述** **题目编号**:P1464 **题目名称**:Function **考察重点**:递归、记忆化搜索(避免重复计算) --- #### **题目描述** 定义一个递归函数 $w(a, b, c)$,规则如下: 1. 若 $a \leq 0$ 或 $b \leq 0$ 或 $c \leq 0$,返回 $1$。 2. 若 $a > 20$ 或 $b > 20$ 或 $c > 20$,返回 $w(20, 20, 20)$。 3. 若 $a < b$ 且 $b < c$,返回 $w(a, b, c-1) + w(a, b-1, c-1) - w(a, b-1, c)$。 4. 其他情况返回: $$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$,以 `-1 -1 -1` 结束。 **输出**:按格式输出 $w(a, b, c)$ 的结果。 --- #### **解题思路** 1. **直接递归的问题** 直接按题意递归会导致大量重复计算,时间复杂度为指数级,无法通过题目时间限制。 2. **优化方法:记忆化搜索** - 使用三维数组 `memo[21][21][21]` 存储已计算的结果。 - 若结果已存储,直接返回;否则计算后存储,避免重复计算。 3. **参数预处理** - 若 $a, b, c$ 中任意值超过 $20$,统一视为 $20$(题目规则2)。 - 若任意值小于等于 $0$,直接返回 $1$(题目规则1)。 --- #### **代码实现** ```c #include <stdio.h> #include <string.h> int memo[21][21][21]; // 记忆化数组 int w(int a, int b, int c) { // 边界条件处理 if (a <= 0 || b <= 0 || c <= 0) return 1; if (a > 20 || b > 20 || c > 20) return w(20, 20, 20); // 检查是否已计算过 if (memo[a][b][c] != -1) return memo[a][b][c]; // 递归计算并存储结果 if (a < b && b < c) { memo[a][b][c] = w(a, b, c-1) + w(a, b-1, c-1) - w(a, b-1, c); } else { memo[a][b][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); } return memo[a][b][c]; } int main() { int a, b, c; memset(memo, -1, sizeof(memo)); // 初始化记忆数组为-1(未计算) while (1) { scanf("%d%d%d", &a, &b, &c); if (a == -1 && b == -1 && c == -1) break; printf("w(%d, %d, %d) = %d\n", a, b, c, w(a, b, c)); } return 0; } ``` --- #### **关键点解释** 1. **记忆化数组** - 大小为 $21 \times 21 \times 21$,因为参数超过 $20$ 会被截断为 $20$。 - 初始值为 `-1`,表示未计算。 2. **递归终止条件** - 参数小于等于 $0$ 时返回 $1$。 - 参数超过 $20$ 时递归调用 `w(20, 20, 20)`。 3. **时间复杂度优化** - 每个三元组 $(a, b, c)$ 仅计算一次,时间复杂度降至 $O(21^3)$。 --- #### **测试用例示例** 输入: ``` 1 1 1 2 2 2 -1 -1 -1 ``` 输出: ``` w(1, 1, 1) = 2 w(2, 2, 2) = 4 ``` --- #### **总结** 通过记忆化搜索将指数级复杂度优化为线性,确保在合理时间内完成计算。代码需注意参数预处理和记忆化数组的初始化。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值