【问题标题】:Why is memoization giving the wrong output?为什么 memoization 会给出错误的输出?
【发布时间】:2020-12-24 20:10:22
【问题描述】:

我正在尝试使用递归+记忆来解决问题。它只是通过额外的start+3 步骤修改了斐波那契,只能执行K 次。这是我想出的递归代码:

#include <iostream>
using namespace std;

int helper(int start, int N, int K) {
    // cout<<start<<" "<<N<<" "<<K<<"\n";
    if(start>N) return 0;
    if(start==N) return 1;
    
    int ans=0;
    ans=helper(start+1, N, K) + helper(start+2, N, K);
    if(K>0) {
        K--;
        ans=ans+helper(start+3, N, K);
    }
    
    return ans;
}

int main() {
    int T;
    cin>>T;
    while(T--) {
        int N, K;
        cin>>N>>K;
        cout<<helper(0, N, K)<<"\n";
    
    }
    
    return 0;
}

只需记住它并取模 10^9+7(问题需要我这样做),我有:

#include <iostream>
#include <vector>
using namespace std;

vector<long long int> dp;
const unsigned int M = 1000000007;

int helper(long long int start, long long int N, int K) {
    // cout<<start<<" "<<N<<" "<<K<<"\n";
    if(start>N) return 0;
    if(start==N) return 1;
    if(dp[start]!=0) {
        return dp[start];
    }
    
    int ans=0;
    ans=(helper(start+1, N, K)%M + helper(start+2, N, K)%M)%M;
    if(K>0) {
        K--;
        ans=(ans%M+helper(start+3, N, K)%M)%M;
    }
    
    return dp[start]=ans;
}

int main() {
    int T;
    cin>>T;
    while(T--) {
        long long int N;
        int K;
        cin>>N>>K;
        dp.clear();
        dp.resize(N+5, 0);
        cout<<helper(0, N, K)<<"\n";
    }
    
    return 0;
}

代码完全相同,但用于记忆和取模。当我在以下输入上运行它时:

1
7 1

我在第一种情况下得到41,而在第二种情况下得到44。显然,我进行了调试,并且预计会出现一些记忆或模数问题。但是,我注意到一些 evaluations 不再被计算,由此我得出了递归调用的一些问题。请注意调用 here 和工作代码 sn-ps herehere 的差异。

有人可以指出我缺少什么吗?

【问题讨论】:

  • 注意:我相当确信问题不在于基于上面附加的差异的模数,而且因为我的输入足够小,模数并没有真正产生任何影响。
  • 算法在做什么?看起来像是某种修改后的斐波那契?
  • 是的,没错。修改了斐波那契,增加了一个额外的 start+3 步骤,只能执行 K 次。

标签: c++ algorithm recursion memoization


【解决方案1】:

您将完全基于start 的结果缓存在db 中,而完全忽略K。但是helper(0, 7, 0)helper(0,7,7) 需要在每个索引处缓存完全不同的数字,这取决于K 剩余的内容。所以你需要缓存index也基于K

我看到了三种优化方法:

  • 有一个缓存缓存。 db[start] 将是 std::vector,您将在该向量中使用索引 K 来访问您的项目。这会导致使用显着更多的内存。
  • 放弃std::vector 并使用std::unordered_map,其中您的密钥是一对(startK)。 (可能是std::pair&lt;int, int&gt;,但最好使用名称更好的结构。)这应该会使用更少的内存,而速度几乎不会损失。
  • 仅在 K==0 时缓存值。这不会增加您的缓存大小,但是当K 很大时,您也会失去很多缓存优势。

【讨论】:

  • 啊,太好了!我没有意识到这一点。谢谢! :)
猜你喜欢
  • 1970-01-01
  • 2021-05-26
  • 2021-02-10
  • 2017-09-21
  • 1970-01-01
  • 2020-08-22
  • 2019-06-06
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多