给你一根长度为n的绳子,请把绳子剪成m段,记每段绳子长度为k[0],k[1]...k[m-1],求k[0]k[1]...k[m-1]的最大值。已知绳子长度n为整数,m>1(至少要剪一刀,不能不剪),k[0],k[1]...k[m-1]均要求为整数。
例如,绳子长度为8时,把它剪成3-3-2,得到最大乘积18;绳子长度为3时,把它剪成2-1,得到最大乘积2
我们假定绳子长度为n,由于题目要求至少剪一刀,我们假设剪一刀后,将绳子切为i 和n-i两段,则f(n) = max(f(i) * f(n-i))。
举个例子来帮助我们整理思路:假设现在n=20,我们将其剪为5 和15,而求f(15) 时,我们将其剪为5 和10,我们发现子问题在求解上有重合。所以我们先求解子问题,保存子问题结果,自底向上求解最优解。
tips:当我们将绳子切为i 和 n -i 两段后,f(i) ,f(n-i)与f(n)在求解时有些许不同:对于题目要求至少剪一刀,所以对n来说,不能不剪;而对于f(i),f(n-i), 若其不剪结果比剪后结果大,则保持其完整状态。
那这个剪与不剪的边界是多少?下面我们简单来证明一下:
假设n是偶数,我们只切一刀,则f(n) = (n/2) * (n/2), 令f(n) >= n;求得n>=4;
假设n是奇数,我们切一刀后,fn = (n +1)/2 * (n-1)/2, 令f(n) >= n;求得n>4;
所以切与不切的边界为n=4
即对 i<4 (或n-i <4)时,f(i) = i, 即不切比切结果更大。而当n < 4时,至少f(n) 为切一刀后的最大结果。
def cut_rope(n):
if n < 2:
return 0
if n == 2:
return 1 # 1*1
if n == 3:
return 2 # 1 * 2
# 将其切为i, n-i两部分
area_max = {}
area_max[0] = 0
area_max[1] = 1
area_max[2] = 2
area_max[3] = 3 # 不切时最大
# 从n=4开始,不切的最大值小于等于切后的最大值
m = 4
while m <= n:
t = 0
for i in range(1, m//2 + 1):
t = max(t, area_max[i] * area_max[m-i])
area_max[m] = t
m += 1
return area_max[n]
# cut_rope(10)
36