小团有一个由N个节点组成的二叉树,每个节点有一个权值。定义二叉树每条边的开销为其两端节点权值的乘积,二叉树的总开销即每条边的开销之和。小团按照二叉树的中序遍历依次记录下每个节点的权值,即他记录下了N个数,第i个数表示位于中序遍历第i个位置的节点的权值。之后由于某种原因,小团遗忘了二叉树的具体结构。在所有可能的二叉树中,总开销最小的二叉树被称为最优二叉树。现在,小团请小美求出最优二叉树的总开销。
小团有一个由N个节点组成的二叉树,每个节点有一个权值。定义二叉树每条边的开销为其两端节点权值的乘积,二叉树的总开销即每条边的开销之和。小团按照二叉树的中序遍历依次记录下每个节点的权值,即他记录下了N个数,第i个数表示位于中序遍历第i个位置的节点的权值。之后由于某种原因,小团遗忘了二叉树的具体结构。在所有可能的二叉树中,总开销最小的二叉树被称为最优二叉树。现在,小团请小美求出最优二叉树的总开销。
第一行输入一个整数N(1<=N<=300),表示二叉树的节点数。
第二行输入N个由空格隔开的整数,表示按中序遍历记录下的各个节点的权值,所有权值均为不超过1000的正整数。
输出一个整数,表示最优二叉树的总开销。
5 7 6 5 1 3
45
最优二叉树如图所示,总开销为7*1+6*5+5*1+1*3=45。
const readline=require('readline'); const rl=readline.createInterface({ input:process.stdin, output:process.stdout }) const arr=[]; rl.on('line',function(line){ arr.push(line); if(arr.length===2){ let len=Number(arr[0]); let w=arr[1].split(' ').map(Number); w.unshift(0); //1.dp[low][high][root]表示以root为根节点, //其左/右子树节点范围在data[low,high]内的最小开销(左或者右,只有一边) //2.len+1是因为需要有一个虚拟的根节点 let dp=Array.from({length:len+1}, ()=>Array.from({length:len+1},()=>Array(len+1).fill(-1))); const dfs=(low,high,root)=>{ if(low>high) return 0; //如果访问过则直接返回 if(dp[low][high][root]!=-1) return dp[low][high][root]; //在low~high每个位置都有可能作为根节点 let cost=Infinity; for(let i=low;i<=high;i++){ let left=dfs(low,i-1,i); let right=dfs(i+1,high,i); cost=Math.min(cost,left+right+w[i]*w[root]); } return dp[low][high][root]=cost; } console.log(dfs(1,len,0)); //next arr.length=0; } })