【问题标题】:Simple recursion/dp - help trace简单递归/dp - 帮助跟踪
【发布时间】:2013-12-30 18:59:51
【问题描述】:

这是来自 CodeChef 的 dp 教程,我正在跟踪它。

详细信息:当我输入 if 子句时 - 我打印“STEP 1”/step2/step3。 该程序运行良好。

#include <iostream>
#include <string.h>
#include <stdio.h>
using namespace std ;
#define min(a,b) ( (a) < (b) ? (a) : (b))

int memo[10 + 1] ;
void reset_memo()
{
    cout << endl ;
    cout << "RESETTING MEMO" << endl ;
    for (int i = 0 ; i < 11 ; i++) {
        memo[i] = -1 ;
    }
}

int getMinSteps(int n)
{
    cout << "======current n : " << n <<  " ===============" << endl ;
    if (n == 1) {
        cout << "BASE CASE n = 1 and returning 0..." << endl ;
        return 0;
    }  // base case

    if (memo[n] != -1) {
        return memo[n];
    } // we have solved it already :)

    cout << "STEP 1 " << endl ;
    int r = 1 + getMinSteps(n - 1);    // '-1' step .  'r' will contain the optimal answer finally

    if (n % 2 == 0) {
        cout << " STEP 2: "  << endl ;
        r = min(r , 1 + getMinSteps(n / 2)) ;
    }  //  '/2' step

    if (n % 3 == 0) {
        cout << " STEP 3: "   << endl ;
        r =  min(r , 1 + getMinSteps(n / 3)) ;
    }  //  '/3' step

    memo[n] = r ;  // save the result. If you forget this step, then its same as plain recursion.
    return r;
}

我花了 5 个小时试图了解一个小细节:

输出:

重置备忘录

输入下一个数字

2

===============当前n 2 ===============

第 1 步:

===============当前n 1 ===============

BASE CASE n = 1 并返回 0...

第 2 步:

===============当前n 1 ===============

BASE CASE n = 1 并返回 0...

===============当前 n 1 ===============

BASE CASE n = 1 并返回 0...

结果 1

重置备忘录 输入下一个数字


为什么将最后一段黑色突出显示的代码称为“BASE CASE ....”?

我显然没有看到它!它应该只存在一次 请帮忙弄清楚 - 我看不出究竟在哪里发生了额外的电话!

【问题讨论】:

  • 案例n=2有两个getMinSteps调用:n-1和n/2
  • 如果您显示实际调用getMinSteps()的代码可能会有所帮助...

标签: c++ debugging recursion dynamic-programming


【解决方案1】:

我在调试器下测试了程序,min( ) 导致getMinSteps(n / 2) 被调用两次。这是因为您拥有的宏定义使用 b 两次 #define min(a,b) ( (a) &lt; (b) ? (a) : (b)) 导致副作用。尝试使用 std:min 代替。

这是n % 2 == 0案例的另一种解决方法

#include <iostream>
#include <string.h>
#include <stdio.h>
using namespace std ;
#define min(a,b) ( (a) < (b) ? (a) : (b))

int memo[10 + 1] ;



void reset_memo()
{
    cout << endl ;
    cout << "RESETTING MEMO" << endl ;
    for (int i = 0 ; i < 11 ; i++) {
        memo[i] = -1 ;
    }
}

int getMinSteps(int n)
{
    cout << "======current n : " << n <<  " ===============" << endl ;
    if (n == 1) {
        cout << "BASE CASE n = 1 and returning 0..." << endl ;
        return 0;
    }  // base case

    if (memo[n] != -1) {
        return memo[n];
    } // we have solved it already :)

    cout << "STEP 1 " << endl ;
    int r = 1 + getMinSteps(n - 1);    // '-1' step .  'r' will contain the optimal answer finally

    if (n % 2 == 0) {
        cout << " STEP 2: "  << endl ;
        int v =  getMinSteps(n / 2); // <--- so getMinSteps will be called only once!
        r = min(r , 1 + v) ;
    }  //  '/2' step

    if (n % 3 == 0) {
        cout << " STEP 3: "   << endl ;
        r =  min(r , 1 + getMinSteps(n / 3)) ;
    }  //  '/3' step

    memo[n] = r ;  // save the result. If you forget this step, then its same as plain recursion.
    return r;
}

int main(){
    reset_memo();
    getMinSteps(2);
    getchar();
    getchar();

}

【讨论】:

  • 怎么样?为什么宏定义会导致它计算两次?
  • 你能解释一下吗?如果将 min(a,b) 写成常规函数会怎样?
  • @ERJAN 因为宏只是预编译文本替换。如果你写min(x+1,x-1),编译器实际看到的是((x+1) &lt; (x-1) ? (x+1) : (x-1))。在ab 都没有副作用的情况下,这通常没问题,但效率低下。在ab 有副作用的情况下,例如调用函数,结果可能与预期不完全一致,这就是为什么使用(可能是staticinline 函数要好得多的一个重要原因。
猜你喜欢
  • 1970-01-01
  • 2016-04-13
  • 1970-01-01
  • 1970-01-01
  • 2022-01-23
  • 2010-10-25
  • 1970-01-01
  • 1970-01-01
  • 2011-06-21
相关资源
最近更新 更多