给你一根长度为n的绳子,请把绳子剪成m段(m、n都是整数, n>1并且m>1),每段绳子的长度记为k[0],k[1],...,k[m]。
请问k[0]*k[1]*...*k[m]可能的最大乘积是多少?
这里设置一个res列表
来跟踪当前数字的最大乘积,那么后一个数字ni
的最大乘积则为两边乘积的最大值,即max_value = max(res[nj)* res[ni-nj)
,其中nj∈[1, n//2+1]
。运用动态规划解决问题的关键是具备从上到下分析问题、从下到上解决问题的能力。
应用动态规划
求解的问题的特点:
-
求一个问题的最优解,而且该问题能够分解成若干个子问题,并且子问题之间还有重叠的更小的子问题。
-
分析能够把大问题分解成小问题,分解后的每个小问题也存在最优解,而把小问题的最优解组合起来能够得到整个问题的最优解。
-
把大问题分解成若干个小问题,这些小问题之间还有相互重叠的更小的子问题。
-
由于子问题在分解大问题的过程中重复出现,为了避免重复求解子问题,可以用从下往上的顺序先计算小问题的最优解并存储下来,再以此为基础求取大问题的最优解。从上往下分析问题,从下往上求解问题。
应用贪婪算法
解决问题的时候,每一步都可以做出一个贪婪的选择,基于这个选择,确定能够得到最优解。
def max_product_after_cutting(n):
if n < 2:
return 0
if n == 2:
return 1
if n == 3:
return 2
res = [0, 1, 2, 3]
for ni in range(4, n+1):
max_value = 0
for nj in range(1, ni//2 + 1):
current = res[nj] * res[ni-nj]
if current > max_value:
max_value = current
else:
break
res.append(max_value)
return res[-1]
此外,可以根据值的规律来求解。即当n>=5
时,尽可能多地剪长度为3的绳子;当剩下的绳子长度为4时,把绳子剪成两段长度为2的绳子。也就是说,根据n % 3
的值存在三种情况:
-
n % 3 == 2
的时候,长度为3和为2的绳子数目分别为n // 3, 1
。 -
n % 3 == 1
的时候,长度为3和为2的绳子数目分别为n // 3 - 1、 2
。 -
n % 3 == 0
的时候,长度为3和为2的绳子数目分别为n // 3, 0
。
def max_product_after_cutting(n):
if n < 2:
return 0
if n == 2:
return 1
if n == 3:
return 2
three = n // 3
if n - three*3 == 1:
three -= 1
two = (n - three*3) // 2
return pow(2, two) * pow(3, three)
(最近更新:2019年09月21日)