具体到本题上,我们在朴素的 DFS 的基础上,增加一个数组 mem 来记录每个 dfs(pos,tleft) 的返回值。刚开始把 mem 中每个值都设成 -1(代表没求解过)。每次需要访问一个状态时,如果相应状态的值在 mem 中为 -1,则递归访问该状态。否则我们直接使用 mem 中已经存储过的值即可。
通过这样的处理,我们确保了每个状态只会被访问一次,因此该算法的的时间复杂度为 O(TM)。
实现
[list2tab]
C++
int n, t;int tcost[103], mget[103];int mem[103][1003];int dfs(int pos, int tleft) { if (mem[pos][tleft] != -1) return mem[pos][tleft]; // 已经访问过的状态,直接返回之前记录的值 if (pos == n + 1) return mem[pos][tleft] = 0; int dfs1, dfs2 = -INF; dfs1 = dfs(pos + 1, tleft); if (tleft >= tcost[pos]) dfs2 = dfs(pos + 1, tleft - tcost[pos]) + mget[pos]; // 状态转移 return mem[pos][tleft] = max(dfs1, dfs2); // 最后将当前状态的值存下来}int main() { memset(mem, -1, sizeof(mem)); cin >> t >> n; for (int i = 1; i <= n; i++) cin >> tcost[i] >> mget[i]; cout << dfs(1, t) << endl; return 0;}
Python
tcost = [0] * 103mget = [0] * 103mem = [[-1 for i in range(1003)] for j in range(103)]def dfs(pos, tleft): if mem[pos][tleft] != -1: return mem[pos][tleft] if pos == n + 1: mem[pos][tleft] = 0 return mem[pos][tleft] dfs1 = dfs2 = -INF dfs1 = dfs(pos + 1, tleft) if tleft >= tcost[pos]: dfs2 = dfs(pos + 1, tleft - tcost[pos]) + mget[pos] mem[pos][tleft] = max(dfs1, dfs2) return mem[pos][tleft]t, n = map(lambda x: int(x), input().split())for i in range(1, n + 1): tcost[i], mget[i] = map(lambda x: int(x), input().split())print(dfs(1, t))