C语言-算法-搜索剪枝与记忆化搜索

Function

题目描述

对于一个递归函数 w ( a , b , c ) w(a,b,c) w(a,b,c)

  • 如果 a ≤ 0 a \le 0 a0 b ≤ 0 b \le 0 b0 c ≤ 0 c \le 0 c0 就返回值$ 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(a1,b,c)+w(a1,b1,c)+w(a1,b,c1)w(a1,b1,c1)

这是个简单的递归函数,但实现起来可能会有些问题。当 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 1T105

代码实现

#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 2417161(从 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 1R,C100

代码

#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]; // 返回当前点的最长滑坡长度
}
  • 11
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值