Function
题目描述
对于一个递归函数 w ( a , b , c ) w(a,b,c) w(a,b,c)
- 如果 a ≤ 0 a \le 0 a≤0 或 b ≤ 0 b \le 0 b≤0 或 c ≤ 0 c \le 0 c≤0 就返回值$ 1$。
- 如果 a > 20 a>20 a>20 或 b > 20 b>20 b>20 或 c > 20 c>20 c>20 就返回 w ( 20 , 20 , 20 ) w(20,20,20) w(20,20,20)
- 如果 a < b a<b a<b 并且 b < c b<c 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 ) w(a-1,b,c)+w(a-1,b-1,c)+w(a-1,b,c-1)-w(a-1,b-1,c-1) 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 a,b,c a,b,c 均为 15 15 15 时,调用的次数将非常的多。你要想个办法才行。
注意:例如 w ( 30 , − 1 , 0 ) w(30,-1,0) w(30,−1,0) 又满足条件 1 1 1 又满足条件 2 2 2,请按照最上面的条件来算,答案为 1 1 1。
输入格式
会有若干行。
并以 − 1 , − 1 , − 1 -1,-1,-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 ] [-9223372036854775808,9223372036854775807] [−9223372036854775808,9223372036854775807] 之间,并且是整数。
保证不包括 − 1 , − 1 , − 1 -1, -1, -1 −1,−1,−1 的输入行数 T T T 满足 1 ≤ T ≤ 1 0 5 1 \leq T \leq 10 ^ 5 1≤T≤105。
代码实现
#include <stdio.h>
#define MAX 21
long long w(long long a, long long b, long long c); // 定义函数来计算w(a, b, c)的值
long long dp[MAX][MAX][MAX]; // 定义一个三维数组dp来存储已经计算过的w(a, b, c)的值int main()
{long long a, b, c;while (scanf("%lld %lld %lld", &a, &b, &c) != EOF){if (a == -1 && b == -1 && c == -1){break;}printf("w(%lld, %lld, %lld) = %lld\n", a, b, c, w(a, b, c));}return 0;
}long long w(long long a, long long b, long long c) // 定义函数来计算w(a, b, c)的值
{if (a <= 0 || b <= 0 || c <= 0){return 1;}else if (a > 20 || b > 20 || c > 20){return w(20, 20, 20);}else if (dp[a][b][c] != 0) // 如果已经计算过w(a, b, c),那么直接返回对应的值{return dp[a][b][c];}if (a < b && b < c){dp[a][b][c] = w(a, b, c - 1) + w(a, b - 1, c - 1) - w(a, b - 1, c);}else{dp[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 dp[a][b][c];
}
[SHOI2002] 滑雪
题目描述
Michael 喜欢滑雪。这并不奇怪,因为滑雪的确很刺激。可是为了获得速度,滑的区域必须向下倾斜,而且当你滑到坡底,你不得不再次走上坡或者等待升降机来载你。Michael 想知道在一个区域中最长的滑坡。区域由一个二维数组给出。数组的每个数字代表点的高度。下面是一个例子:
1 2 3 4 5
16 17 18 19 6
15 24 25 20 7
14 23 22 21 8
13 12 11 10 9
一个人可以从某个点滑向上下左右相邻四个点之一,当且仅当高度会减小。在上面的例子中,一条可行的滑坡为 24 − 17 − 16 − 1 24-17-16-1 24−17−16−1(从 24 24 24 开始,在 1 1 1 结束)。当然 25 25 25- 24 24 24- 23 23 23- … \ldots …- 3 3 3- 2 2 2- 1 1 1 更长。事实上,这是最长的一条。
输入格式
输入的第一行为表示区域的二维数组的行数 R R R 和列数 C C C。下面是 R R R 行,每行有 C C C 个数,代表高度(两个数字之间用 1 1 1 个空格间隔)。
输出格式
输出区域中最长滑坡的长度。
样例 #1
样例输入 #1
5 5
1 2 3 4 5
16 17 18 19 6
15 24 25 20 7
14 23 22 21 8
13 12 11 10 9
样例输出 #1
25
提示
对于 100 % 100\% 100% 的数据, 1 ≤ R , C ≤ 100 1\leq R,C\leq 100 1≤R,C≤100。
代码
#include <stdio.h>
int max(int a, int b); // 求两个数的最大值
int dfs(int x, int y); // 深度优先搜索
#define MAX 10000
int R, C; // 区域的行数和列数
int height[MAX][MAX]; // 存储每个点的高度
int dp[MAX][MAX]; // 存储每个点的最长滑坡长度
int dx[4] = {-1, 1, 0, 0}; // 行
int dy[4] = {0, 0, -1, 1}; // 列int main()
{int i, j, longest;scanf("%d %d", &R, &C);longest = 0; // 初始化最长滑坡长度for (i = 0; i < R; i++) // 输入高度{for (j = 0; j < C; j++){scanf("%d", &height[i][j]);}}for (i = 0; i < R; i++) // 对每个点进行深度优先搜索{for (j = 0; j < C; j++){longest = max(longest, dfs(i, j)); // 更新最长滑坡长度}}printf("%d\n", longest); // 输出最长滑坡长度return 0;
}int max(int a, int b) // 求两个数的最大值
{if (a > b){return a;}else{return b;}
}int dfs(int x, int y) // 深度优先搜索
{int i, nx, ny;if (dp[x][y] != 0) // 如果已经计算过该点的最长滑坡长度,则直接返回{return dp[x][y];}dp[x][y] = 1; // 初始化为1,表示至少有一个点(及自身)for (i = 0; i < 4; i++) // 遍历四个方向{nx = x + dx[i];ny = y + dy[i];// 如果新的点在区域内,并且高度小于当前点的高度if (nx >= 0 && nx < R && ny >= 0 && ny < C && height[nx][ny] < height[x][y]){dp[x][y] = max(dp[x][y], dfs(nx, ny) + 1); // 更新当前点的最长滑坡长度}}return dp[x][y]; // 返回当前点的最长滑坡长度
}