【发布时间】:2018-10-02 11:41:35
【问题描述】:
我有一个用于赋值的递归函数。但是,部分要求是通过利用记忆来降低复杂性。
该功能的工作原理类似于移动点击游戏。用户可以执行 a) 点击 b) 升级。该函数找到达到指定数量的最少点击次数。用户可以跳过关卡 - 从而绕过该关卡的成本。
例如:
Levels: 0, 1, 2.
Cost of upgrades: 0, 5, 8.
Money per tap: 2, 4, 9.
其中一条路线,所需金额为 $15:
- 点击三次可获得 2 美元 x 3 美元。 (还剩 6 美元。)
- 升级只需 5 美元(还剩 1 美元。)
- 点击两次可获得 $4 * 2 + $1 美元。 (还剩 9 美元。)
- 8 美元升级(还剩 1 美元。)
- 点按两次即可达到所需金额($19 > $15。)
总共 3 + 2 + 2 = 7 次点击。
更有效的路线是:
- 点击四次可获得 2 美元 x 4 美元。 (还剩 8 美元。)
8 美元升级,跳过二级升级。 (还剩 0 美元。)
点按两次即可达到所需金额($18 > $15。)
总共 4 + 2 = 6 次点击。
现在我有一个适用于上述内容的递归程序。我尝试使用 2D 数组 cache[levels][amount] 来记忆程序,其中存储每个级别/数量的抽头并在需要时访问。
一个最小的工作解决方案如下:
import java.io.*;
import java.math.*;
import java.util.*;
class IdleGame {
private static int fork(int current, int required, int level, int taps, int[] values, int[] costs, int maxLevel,
int[][] cache) {
int first = Integer.MAX_VALUE;
int second = Integer.MAX_VALUE;
if (current >= required) {
return taps;
}
//upgrade path, call recursively if available.
for (int i = level + 1; i <= maxLevel; i++) {
if (current >= costs[i]) {
if (cache[i][current] == 0) {
first = fork(current - costs[i], required, i, taps, values, costs, maxLevel, cache);
cache[i][current] = first;
} else {
// System.out.println("First");
first = cache[i][current];
}
}
}
if (cache[level][current] == 0) {
second = fork(current + values[level], required, level, taps + 1, values, costs, maxLevel, cache);
cache[level][current] = second;
} else {
// System.out.println("Second");
second = cache[level][current]--;
}
return first < second ? first : second;
};
public static void main(String[] args) {
int[] values = {2,4,9};
int[] costs = {0,5,8};
int[][] cache = new int[3][16];
int solution = fork(0, 15, 0, 0, values, costs, 2, cache);
System.out.println(solution);
}
}
但是,这个解决方案对于我的测试用例来说不够快。据我所知,当有另一个递归函数实例调用相同的 level/value 时,我使用记忆值,这发生在两个递归函数交叉时,即具有相同的参数。
任何指导将不胜感激。
【问题讨论】:
-
你只存储第二个值而不存储第一个值有什么原因吗?还是这已经是您的问题了?
-
第一个值实际上并没有修改抽头的数量,即它只是一个升级路径(所以只修改了成本)。升级后,再次递归调用该函数,这一次,它将属于
second的情况。 -
第一个值有什么关系?每次使用相同的值调用该方法时,您都会重新计算它,这会错过记忆的全部要点。
-
你的意思是我应该尝试将
if/elsememoization 添加到升级(第一个)块吗?我这样做了,但我的时间复杂度仍然失败。
标签: java recursion memoization