题目描述
思路
其实这道题的示例给足了暗示。如下图所示,上面一级的答案就是cut的左区间的最小代价+cut的右区间的最小代价+当前长度。
于是,你可以胡诌出一个差不多的状态转移方程:
其中,和表示区间的端点,第三维度记录剩余可以用的切割,这个信息将递归到下一个子问题。于是你可以写出我的第一个朴素无优化的代码。然后你发现里面怎么没开@cache?因为你把set作为状态存进去了,然而cache是unhashable,所以会报错。这一版的代码只能过12个样例。
看来不能用set来记录cuts,那怎么办呢?也好处理,你可以对cuts进行排序,然后每次传递剩余可用cuts信息的时候,只需要传递可用cuts的下标区间就行了。如果子问题发现下标区间违法,那么代表没有可用切割,直接返回代价0即可。
代码
朴素,无优化
from typing import Set
class Solution:
def minCost(self, n: int, cuts: List[int]) -> int:
# @cache
def dfs(i : int , j : int , s : Set[int] ) -> int :
if j <= i : return 0
if len(s) == 0 :
return 0
# 枚举 针对[i,j]应该使用哪一刀
ans = inf
for cut in s :
# 使用cut cut必定存在于i和j之间
# 让s站队
left_s = set()
right_s = set()
for x in s :
if x < cut : left_s.add(x)
elif x > cut : right_s.add(x)
ans = min(ans, dfs(i,cut,left_s) + dfs(cut,j,right_s))
ans += j - i
return ans
return dfs(0,n,set(cuts))
记忆化搜索
class Solution:
def minCost(self, n: int, cuts: List[int]) -> int:
cuts.sort()
@cache
def dfs(i : int , j : int , start_cut : int , end_cut : int ) -> int :
if j <= i : return 0
if end_cut < start_cut : # 没有切割操作
return 0
# 枚举 针对[i,j]应该使用哪一刀
ans = inf
for cut_idx in range(start_cut , end_cut + 1) :
ans = min(ans,
dfs(i,cuts[cut_idx], start_cut , cut_idx-1) \
+ dfs( cuts[cut_idx], j,cut_idx +1 , end_cut))
ans += j - i
return ans
return dfs(0,n,0,len(cuts)-1)