import java.util.*;
/**
* NC393 取金币
* @author d3y1
*/
public class Solution {
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param coins int整型一维数组
* @return int整型
*/
public int getCoins (ArrayList<Integer> coins) {
return solution(coins);
}
/**
* 动态规划
*
* 相似 -> NC326 能量项链
*
* dp[i][j]表示区间[i,j]能得到的最多积分
*
* { Math.max(dp[i][j], dp[k+1][j]+coins[i-1]*coins[k]*coins[j+1]) , k=i && 1<=i<=j<=n
* dp[i][j] = { Math.max(dp[i][j], dp[i][k-1]+coins[i-1]*coins[k]*coins[j+1]) , k=j && 1<=i<=j<=n
* { Math.max(dp[i][j], dp[i][k-1]+dp[k+1][j]+coins[i-1]*coins[k]*coins[j+1]) , i<k<j && 1<=i<=j<=n
*
* @param coinList
* @return
*/
private int solution(ArrayList<Integer> coinList){
int n = coinList.size();
int[] coins = new int[n+2];
for(int i=0; i<n; i++){
coins[i+1] = coinList.get(i);
}
coins[0] = 1;
coins[n+1] = 1;
int[][] dp = new int[n+2][n+2];
// 滑动窗口
for(int gap=0; gap<n; gap++){
// 区间[i,j]能得到的最多积分
for(int i=1,j=i+gap; j<=n; i++,j++){
// [i,k-1] k [k+1,j] <- k:区间[i,j]最后选择金币位置索引
for(int k=i; k<=j; k++){
// 最后选左边界
if(k == i){
dp[i][j] = Math.max(dp[i][j], dp[k+1][j]+coins[i-1]*coins[k]*coins[j+1]);
}
// 最后选右边界
else if(k == j){
dp[i][j] = Math.max(dp[i][j], dp[i][k-1]+coins[i-1]*coins[k]*coins[j+1]);
}
// 最后选区间中间
else{
dp[i][j] = Math.max(dp[i][j], dp[i][k-1]+dp[k+1][j]+coins[i-1]*coins[k]*coins[j+1]);
}
}
}
}
return dp[1][n];
}
}