- 树形DP。
- 备忘录减少算法复杂度(-1)说明没有访问过。里面保存的就是最小,所以直接用就行
- father这个假节点很重要。
#include<bits/stdc++.h>
using namespace std;
const int maxN = 301;
vector<int> nodes;
int ans[maxN][maxN][maxN];//动态转移方程
int dp(int l ,int r, int father){
//base case
if(l>r) return 0;//这个树的根目前在最左边,没有左子树
//备忘录剪枝(如果以及有了结果,啧直接返回这个结果)
if(ans[l][r][father]!=-1) return ans[l][r][father];
int res = INT_MAX;
// 这些节点中每个均可能做根 需要遍历一下
for(int i = l;i<=r;i++){
//分别作为father,左子树遍历的结果,以及对应右子树遍历的结果
int left = dp(l,i-1,i);
int right = dp(i+1,r,i);
// 总最小=min(左子树+右子树+选出的根节点值*father节点值)
res= min(res,left+right+ nodes[i]*nodes[father]);
}
//备忘录记下已经取得的值
return ans[l][r][father] = res;
}
int main(){
int N,x;
while(cin>>N){
nodes.clear();
nodes.push_back(0);//放入假根
for(int i =0; i<N;i++){
cin>>x;
nodes.push_back(x);
}
memset(ans,-1,sizeof(ans));//默认都为-1
int res = dp(1,N,0);//编号从1,n结点中 轮流取根节点划分左右树,且这个根和0节点链接的最小权重
cout<<res<<endl;
}
return 0;
}