【问题标题】:How could you convert the following recursion with dynamic programming?你怎么能用动态编程来转换下面的递归呢?
【发布时间】:2018-09-11 21:35:24
【问题描述】:

您将如何使用动态规划 (DP) 转换以下递归程序? 我只是在尝试将此代码重新定义为动态编程形式时遇到了一些麻烦。我确定了基本案例和一般案例,并且我知道 DP 是一种“自下而上”的方法。

int add(int, int);

int main()
{
    int x = 0, y = 0;
    printf("Enter positive integers x, y: ");
    scanf("%d %d", &x, &y);

    printf("Result: %d\n", add(x, y));

    return 0;
}

int add(int x, int y)
{
    if(x < 0 || y < 0){
        fprintf(stderr, "Negative Integer received!\n");
        return -1;
    }
    if (x == 1 || y == 1)
        return 1;
    else
        return add(x, y-1) + add(x - 1, y) + add(x-1, y-1);
}

【问题讨论】:

  • 递归真的在那里终止吗?似乎add(x, y, z + 1) 会一直保持下去。
  • DP 可以是自上而下或自下而上的。自上而下仍然是递归的,只是缓存了函数的先前结果。但是你需要先修复你的递归,就像 Ryan 说的那样。
  • 我对参数的数量和递归做了一点修改。这可以转换成dp吗?
  • 你没有在使用前声明add(),所以它会使用可变参数的可变默认提升规则。而add(x, y-1, ) 不会编译
  • return add(x, y-1, ) + add(x - 1, y) + add(x-1, y-1); 是无效的 C 代码。最清楚地发布真实代码。

标签: c algorithm recursion dynamic-programming


【解决方案1】:

为什么要用递归的方式来做呢?有一种迭代方式,迭代“几乎总是”胜过递归。此外它的代码更少:

int DP[500][500];
memset(DP, 0, sizeof(DP));
for(int i=1; i<=x; i++) DP[i][1] = 1;
for(int i=1; i<=y; i++) DP[1][i] = 1;

for(int i=2; i<=x; i++) {
    for(int j=2; j<=y; j++) {
        DP[i][j] = DP[i-1][j-1] + DP[i-1][j] + DP[i][j-1];
    }
}

printf("Result: %d\n", DP[x][y]);

但是如果你坚持递归,你可以通过指针传递你的 DP 数组来运行。并且每次检查你之前是否计算过 DP[i][j],如果是就不要再次计算并返回:

#include <stdio.h>
#include <string.h>

void add(int x, int y, int (*M)[500])
{
    if(M[x][y] > 0) return;

    if (x == 1 || y == 1) {
        M[x][y] = 1;
        return;
    }

    add(x, y-1, M);
    add(x - 1, y, M);
    add(x-1, y-1, M);

    M[x][y] = M[x][y-1] + M[x-1][y] + M[x-1][y-1];
    return;
}

int main()
{
    int x, y;
    printf("Enter x, y: ");
    scanf("%d %d", &x, &y);

    int DP[500][500];
    memset(DP, 0, sizeof(DP));
    add(x, y, DP);

    printf("Result: %d\n", DP[x][y]);

    return 0;
}

【讨论】:

    【解决方案2】:

    您的代码将导致所有可能的 x、y 和 z 整数(负、正)组合的堆栈溢出

    【讨论】:

    • 如果我将参数数量减少到两个呢?喜欢 add(x, y) 吗?
    • 我已经编辑了代码,所以它不会导致溢出错误。那么这将作为 dp 工作吗?
    • 你又错了,如果x=-1和y=-1,你的代码会导致栈溢出
    • 如果我假设 x 和 y 是一个正整数,并分别处理负整数的情况,那会解决你所说的堆栈溢出问题吗?
    • 现在您的代码完美地处理了所有边缘情况,但从数学上讲,您的代码仍然给出了错误的答案。例如输入 x=2 y=2 您的代码给出输出 3 ,其中实际总和为 2+2=4
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-08-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-05
    • 2021-11-16
    • 2018-06-11
    相关资源
    最近更新 更多