题目描述
简言之,就是一串编号为从1到n的首尾相连的环状珠子,每一个珠子有头部标记和尾部标记,第i个珠子的尾部标记是第i+1个珠子的首部标记,第i个珠子的首部标记是第i-1个珠子的尾部标记,可以理解为一个循环链表。
原题链接
链接: 原题
解题思路及代码
思路一:贪心做法
每次找到头部标记最小的珠子作为两个珠子合并时的后一个珠子,这样的话每次合并可以消去一个最小的值,该最小值对后面合并时乘积的影响达到最小,即局部最优解构成整体最优解,符合贪心的思想
#贪心
n=int(input())
lst=list(map(int,input().split()))
sum=0
#需要处理n-1次合并
for i in range(n-1):
pst=lst.index(min(lst))#每次找到最小的值作为要被消除的量,以避免它对后续的乘法造成影响
sum+=lst[pst]*lst[pst-1]*lst[(pst+1)%(n-i)]
lst.remove(lst[pst])
print(sum)
思路二:动态规划
使用动态规划需要考虑三个内容,状态表示、初始状态、转移方程
首先为了解决模拟出循环链表的问题,将输入的列表再copy两份放尾部append一下即可,这是为了保证当需要某一个珠子的尾部标记时需要索引加一,多开几份可以避免index out of range
然后根据之前的经验,这道题和石子合并这道区间合并问题很类似,所以使用区间合并的方法
#状态表示:dp[i][j]表示第i颗珠子到第j颗珠子合成一个珠子所释放的最大能量
#初始状态:dp[i][j]=0
#状态转移:dp[i][j]=max{dp[i][k]+dp[k][j]+a[i]*a[k+1]*a[j+1]}
n=int(input())
lst=list(map(int,input().split()))
lst.extend(lst)
lst.extend(lst)#防止开小
dp=[[0]*n*3 for i in range(3*n)]
ans=0
for lenth in range(2,n+1):
for i in range(2*n-lenth+1):
j=i+lenth-1
for k in range(i,j):
dp[i][j]=max(dp[i][j],dp[i][k]+dp[k+1][j]+lst[i]*lst[k+1]*lst[j+1])
for i in range(n):
ans=max(ans,dp[i][i+n-1])
print(ans)