import java.util.*;
/**
* NC333 加分二叉树
* @author d3y1
*/
public class Solution {
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param scores int整型ArrayList
* @return int整型ArrayList<ArrayList<>>
*/
public ArrayList<ArrayList<Integer>> scoreTree (ArrayList<Integer> scores) {
return solution1(scores);
// return solution2(scores);
}
/**
* 动态规划 + 滑动窗口
*
* dp[i][j]表示节点区间[i,j]所能获得的最高加分
* root[i][j]表示节点区间[i,j]获得最高加分时的根节点编号
*
* { scores.get(i-1) , i=j
* dp[i][j] = { { dp[k][k]+dp[k+1][j] , i<j && k=i
* { max { dp[k][k]+dp[i][k-1] , i<j && k=j
* { { dp[k][k]+dp[i][k-1]*dp[k+1][j] , i<j && i<k<j
*
* @param scores
* @return
*/
private ArrayList<ArrayList<Integer>> solution1(ArrayList<Integer> scores){
int n = scores.size();
int[][] root = new int[n+1][n+1];
int[][] dp = new int[n+1][n+1];
int score;
// 滑动窗口
for(int gap=0; gap<n; gap++){
for(int i=1,j=i+gap; j<=n; i++,j++){
if(gap == 0){
dp[i][j] = scores.get(i-1);
root[i][j] = i;
}else{
for(int k=i; k<=j; k++){
if(k == i){
score = dp[k][k]+dp[k+1][j];
if(score > dp[i][j]){
dp[i][j] = score;
root[i][j] = k;
}
}else if(k == j){
score = dp[k][k]+dp[i][k-1];
if(score > dp[i][j]){
dp[i][j] = score;
root[i][j] = k;
}
}else{
score = dp[k][k]+dp[i][k-1]*dp[k+1][j];
if(score > dp[i][j]){
dp[i][j] = score;
root[i][j] = k;
}
}
}
}
}
}
ArrayList<ArrayList<Integer>> result = new ArrayList<>();
ArrayList<Integer> maxScore = new ArrayList<>();
ArrayList<Integer> seq;
maxScore.add(dp[1][n]);
result.add(maxScore);
seq = preOrder(root, 1, n, new ArrayList<>());
result.add(seq);
return result;
}
/**
* 前序遍历
* @param range
* @param left
* @param right
* @param seq
* @return
*/
private ArrayList<Integer> preOrder(int[][] range, int left, int right, ArrayList<Integer> seq){
if(left > right){
return new ArrayList<>();
}
int root = range[left][right];
seq.add(root);
preOrder(range, left, root-1, seq);
preOrder(range, root+1, right, seq);
return seq;
}
/**
* 动态规划 + 滑动窗口
*
* dp[i][j]表示节点区间[i,j]所能获得的最高加分
*
* map.put(key, value)
* key: i+","+j -> 表示节点区间[i,j]
* value: seq -> 表示节点区间[i,j]获得最高加分时的前序遍历顺序
*
* { scores.get(i-1) , i=j
* dp[i][j] = { { dp[k][k]+dp[k+1][j] , i<j && k=i
* { max { dp[k][k]+dp[i][k-1] , i<j && k=j
* { { dp[k][k]+dp[i][k-1]*dp[k+1][j] , i<j && i<k<j
*
* @param scores
* @return
*/
private ArrayList<ArrayList<Integer>> solution2(ArrayList<Integer> scores){
int n = scores.size();
HashMap<String, ArrayList<Integer>> map = new HashMap<>();
int[][] dp = new int[n+1][n+1];
int score;
String key;
ArrayList<Integer> seq;
// 滑动窗口
for(int gap=0; gap<n; gap++){
for(int i=1,j=i+gap; j<=n; i++,j++){
key = i+","+j;
if(gap == 0){
dp[i][j] = scores.get(i-1);
seq = new ArrayList<>();
seq.add(i);
map.put(key, seq);
}else{
for(int k=i; k<=j; k++){
if(k == i){
score = dp[k][k]+dp[k+1][j];
if(score > dp[i][j]){
dp[i][j] = score;
seq = new ArrayList<>();
seq.addAll(map.get(k+","+k));
seq.addAll(map.get((k+1)+","+j));
map.put(key, seq);
}
}else if(k == j){
score = dp[k][k]+dp[i][k-1];
if(score > dp[i][j]){
dp[i][j] = score;
seq = new ArrayList<>();
seq.addAll(map.get(k+","+k));
seq.addAll(map.get(i+","+(k-1)));
map.put(key, seq);
}
}else{
score = dp[k][k]+dp[i][k-1]*dp[k+1][j];
if(score > dp[i][j]){
dp[i][j] = score;
seq = new ArrayList<>();
seq.addAll(map.get(k+","+k));
seq.addAll(map.get(i+","+(k-1)));
seq.addAll(map.get((k+1)+","+j));
map.put(key, seq);
}
}
}
}
}
}
ArrayList<ArrayList<Integer>> result = new ArrayList<>();
ArrayList<Integer> maxScore = new ArrayList<>();
maxScore.add(dp[1][n]);
result.add(maxScore);
result.add(map.get(1+","+n));
return result;
}
}