这个题解使用动态规划的方法来解决切披萨问题。主要思路如下:
1. 首先预处理得到一个前缀和数组presums,其中presums[r][c]表示披萨从(r,c)位置到披萨右下角的苹果数量。
2. 然后定义一个二维DP数组f,其中f[r][c]表示从(r,c)位置到披萨右下角,切k-1次能够得到的合法方案数。
3. 初始化f数组,对于每个位置(r,c),如果从该位置到披萨右下角还有苹果,则f[r][c]=1,表示还可以进行一次合法切割。
4. 接下来进行k-1轮切割,每一轮都更新f数组。对于当前轮的每个位置(r,c),若该位置下方或右方已经没有苹果,则f[r][c]直接等于下方或右方的f值;否则,f[r][c]等于下方和右方所有合法切割方案数的总和。
5. 最后返回f[0][0]即为最终答案,表示从披萨左上角开始切k-1次能够得到的合法方案总数。
时间复杂度: O(kRC)
空间复杂度: O(RC)
class Solution:
def ways(self, pizza: List[str], k: int) -> int:
R,C=len(pizza),len(pizza[0])
f=[[0]*(C+1) for _ in range(R+1)] # DP数组,f[r][c]表示从(r,c)到右下角切k-1次的合法方案数
presums=[[0]*(C+1) for _ in range(R+1)] # 前缀和数组,presums[r][c]表示(r,c)到右下角的苹果数
# 预处理前缀和数组
for r in range(R-1,-1,-1):
for c in range(C-1,-1,-1):
presums[r][c]=presums[r][c+1]+presums[r+1][c]+int(pizza[r][c]=='A')-presums[r+1][c+1]
if presums[r][c]:
f[r][c]=1 # 初始化f数组,如果(r,c)到右下角有苹果,则可以进行一次合法切割
tot=presums[0][0] # 披萨中苹果的总数
if tot<k:
return 0 # 如果苹果数小于k,无法切成k块
Mode=10**9+7
for _ in range(k-1): # 进行k-1轮切割
cols=[0]*C # 存储当前列的前缀和
for r in range(R-1,-1,-1):
rows=0 # 存储当前行的前缀和
for c in range(C-1,-1,-1):
temp=f[r][c]
if presums[r][c]==presums[r+1][c]: # 下方没有苹果
f[r][c]=f[r+1][c]
elif presums[r][c]==presums[r][c+1]: # 右方没有苹果
f[r][c]=f[r][c+1]
else:
f[r][c]=(rows+cols[c])%Mode # 当前位置的方案数为下方和右方的方案数之和
rows+=temp
cols[c]+=temp
return f[0][0] # 返回最终答案