LC 3257. 放三个车的价值之和最大 II
https://leetcode.cn/problems/maximum-value-sum-by-placing-three-rooks-ii/description/
这题最开始我使用的是剪枝,从上到下进行选择:
- 如果还是剩余两个的话,可以估算upper bound
- 如果还剩一个的话,那么可以精确得到最大值。
使用普通的剪枝方法还过来。然后还有一个优化就是每一行里面只考虑最大的3个值,这样的话可以让剪枝更加高效。代码比较长
class Solution: def maximumValueSum(self, board: List[List[int]]) -> int: n, m = len(board), len(board[0]) MAX_VAL = [[0] * m for _ in range(n)] for i in reversed(range(n)): for j in range(m): MAX_VAL[i][j] = board[i][j] if (i + 1) < n: MAX_VAL[i][j] = max(MAX_VAL[i][j], MAX_VAL[i + 1][j]) MAX_COL = [[] for _ in range(n)] COLS = set() for i in range(n): js = list(range(m)) js.sort(key=lambda x: board[i][x], reverse=True) MAX_COL[i] = js[:3] COLS.update(js[:3]) COLS = list(COLS) import functools @functools.cache def getmax(st, i, k): xs = [] for j in COLS: if st & (1 << j) == 0: xs.append(MAX_VAL[i][j]) xs.sort() return sum(xs[-k:]) inf = 1 << 63 ans = -inf def dfs(st, i, k, now): nonlocal ans if i == n: return bound = getmax(st, i, k) if k == 1: ans = max(ans, bound + now) return # cut branch if now + bound <= ans: return for ii in range(i, n): for j in MAX_COL[ii]: if st & (1 << j): continue v = board[ii][j] dfs(st | (1 << j), ii + 1, k - 1, now + v) dfs(0, 0, 3, 0) return ans
题解里面给的方法更加简单:对于这种3个的题目,可以枚举中间的点,同时更新上下两个点。上下两个点也是只需要维护最大的3个位置就好了。
class Solution: def maximumValueSum(self, board: List[List[int]]) -> int: n, m = len(board), len(board[0]) MAX_VAL = [[0] * m for _ in range(n)] for i in reversed(range(n)): for j in range(m): MAX_VAL[i][j] = board[i][j] if (i + 1) < n: MAX_VAL[i][j] = max(MAX_VAL[i][j], MAX_VAL[i + 1][j]) DOWN = MAX_VAL MAX_VAL = [[0] * m for _ in range(n)] for i in range(n): for j in range(m): MAX_VAL[i][j] = board[i][j] if (i - 1) >= 0: MAX_VAL[i][j] = max(MAX_VAL[i][j], MAX_VAL[i - 1][j]) UP = MAX_VAL ans = -(1 << 63) for i in range(1, n - 1): up = list(range(m)) up.sort(key=lambda x: UP[i - 1][x], reverse=True) up = up[:3] down = list(range(m)) down.sort(key=lambda x: DOWN[i + 1][x], reverse=True) down = down[:3] for j in range(m): for a in up: for b in down: if a == j or b == j or a == b: continue r = board[i][j] + UP[i - 1][a] + DOWN[i + 1][b] ans = max(ans, r) return ans