- 树形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; }