【问题标题】:Memoization in limited space有限空间内的记忆
【发布时间】:2013-03-06 19:24:41
【问题描述】:

在尝试提高我对this contest 的回答速度时,我有一个函数,它采用两个值nk 并产生一个输出。计算是重复的,所以我要记住它。我不能使用二维数组,因为nk 的约束是10^5!所以我正在使用地图:

std::map<std::pair<int,int>,double> m;

double solve(int n, int k)
{
    if(k==0) return n;
    if(k==1) return (n-1)/2.0;

    std::pair<int,int> p = std::make_pair(n,k);
    std::map<std::pair<int,int>,double>::iterator it;

    if( (it=m.find(p)) != m.end())
        return it->second;

    double ans = 0;
    for(int i=1 ; i<=n-1 ; i++)
        ans += solve(i,k-1);
    ans = ans/n;
    m[p] = ans;

    return ans;
}

但显然,这种方法太慢了。我的记忆有问题吗?或者我可以像数组一样获取恒定时间而不是从地图中获取对数?

这个函数解决了这个重复:

f(x,0) = xf(x,1) = (x-1)/2

能否以更好的方式解决这个问题?提前非常感谢。

【问题讨论】:

  • unordered_map 会有所帮助,但您至少需要进行两倍以上的查找。
  • @OliCharlesworth 嗯。显然在我的情况下..
  • 我认为对于这段代码,您可以从分析逻辑中获得更多,而不仅仅是缓存结果。简短的一瞥让我觉得你应该能够在 O(1) 中计算这个,而不是你在这里的 O(n*k)。
  • 鉴于if (k&lt;n-1) 那么结果为零,可以针对这些情况进行一些重要的优化。此外,map 对于相同的数据范围占用 更多 空间,除非它是稀疏的,但快速分析表明您的数据不会稀疏。所以要么(A)使用二维数组,要么(B)只缓存sparcely
  • @Bruce 重复出现和代码不同。我是从 0 开始还是从 1 开始?那么y

标签: c++ map memoization stdmap


【解决方案1】:

小改进:记住 find 返回的迭代器并取消引用它,而不是使用 operator[]。

【讨论】:

  • 这可能是一个相当大的改进。在地图中查找是相当昂贵的。
  • @us2012 对此我深表歉意,我不是故意的。我认为这是次要的,因为 SebastianK 自己也说过。
  • @AlexChamberlain Minor,因为我想通过简化循环可以实现更大的改进。
  • 对于 k == 0 和 k == 1 的情况也不应该被缓存,这弊大于利。
  • @Slava 我试过了;我删除了这两个条件,并用 K=0 和 K=1 初始化了地图中所有可能的 N。没有帮助..
【解决方案2】:

您不必存储二维值数组。代替记忆,转而使用动态编程来解决问题。

为了节省一些时间,请注意f(x, y) = 0 if x &lt;= y

1 &lt;= i &lt;= x - k 计算f(i, 0) 的值并将它们存储到一维数组中。然后计算f(i, 1) 对应2 &lt;= i &lt;= x - k + 1f(i, 2) 对应3 &lt;= i &lt;= x - k + 2,依此类推,直到得到f(i, k - 1) 对应k &lt;= i &lt;= x - 1。然后你可以计算f(x, k)。每一步只需要两个长度为x - k的数组。

计算f(i, j) 需要i - j - 1 加法和除法。所以总时间是 ϴ((x - k)2 k)。但是如果你先计算总和然后除法会更快,因为每个和只是比前一个多一个元素,所以总时间是 ϴ((x - k) k)。

【讨论】:

  • 我认为这比你声称的要多 很多,事实上,我认为这是 i*k 的加法和除法。
猜你喜欢
  • 2023-04-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-05-11
  • 2012-01-04
相关资源
最近更新 更多