小团有一个由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。
我用了两个二维数组,ldp[i][j]表示以以node[j+1]为根节点、node[i]到node[j]作为左子树节点的最优二叉树的权值;rdp[i][j]表示以以node[i-1]为根节点、node[i]到node[j]作为右子树节点的最优二叉树的权值。
其实也用不着初始化,在递推公式里就能完成。
#include <iostream> using namespace std; int ldp[302][302]{}; int rdp[302][302]{}; int node[302]{}; void f(int a, int b) { int x, y; ldp[a][b] = rdp[a][b] = 100000000; for (int i = a; i <= b; ++i) { x = ldp[a][i - 1] + node[i] * node[b + 1] + rdp[i + 1][b]; y = ldp[a][i - 1] + node[i] * node[a - 1] + rdp[i + 1][b]; if (x < ldp[a][b])ldp[a][b] = x; if (y < rdp[a][b])rdp[a][b] = y; } } int main() { int N; cin >> N; for (int i = 1; i <= N; ++i) { cin >> node[i]; } for (int i = 0; i < N; ++i) { for (int j = 1; j <= N-i; ++j) { f(j, j + i); } } cout << ldp[1][N]; return 0; }
#include"bits/stdc++.h" using namespace std; const int N = 310; int w[N]; int f[N][N][N]; int n; int dp(int l, int r, int p) { if(l > r) return 0; if(f[l][r][p] != -1) return f[l][r][p]; int ret = 2e9; for(int i = l; i<=r ; i++) { int left = dp(l,i-1,i); int right = dp(i+1,r,i); ret = min(ret,left + right + w[i]*w[p]); } f[l][r][p] = ret; return ret; } int main() { cin >> n; memset(f,-1,sizeof f); for(int i = 1; i<=n ; i++) cin >> w[i]; cout << dp(1,n,0); return 0; }
import java.io.BufferedReader; import java.io.InputStreamReader; import java.io.IOException; public class Main { static int[][][] mem; static int[] weight; static int n; public static void main(String[] args) throws IOException { BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); n = Integer.parseInt(br.readLine().trim()); String[] strW = br.readLine().trim().split(" "); weight = new int[n]; for(int i = 0; i < n; i++) weight[i] = Integer.parseInt(strW[i]); // mem[l][r][k]表示以weight[l:r]为子节点,以weight[k]为根节点的树开销 mem = new int[n][n][n]; for(int i = 0; i < n; i++){ for(int j = 0; j < n; j++) for(int k = 0; k < n; k++) mem[i][j][k] = -1; } System.out.println(recur(0, n - 1, -1)); } private static int recur(int left, int right, int root) { if(left > right) return 0; if(root >= 0 && mem[left][right][root] != -1) return mem[left][right][root]; int cost = Integer.MAX_VALUE; // [left,right]中的元素轮流做根节点构建二叉树 int leftCost = 0, rightCost = 0; for(int i = left; i <= right; i++){ leftCost = recur(left, i - 1, i); // 左子树开销 rightCost = recur(i + 1, right, i); // 右子树开销 // root=-1时表示初始根节点还没有确定,不会有根节点连接左右子树的边 cost = Math.min(cost, leftCost + rightCost + weight[i]*(root != -1? weight[root]: 0)); } if(root >= 0) mem[left][right][root] = cost; return cost; } }
import java.util.Scanner; import java.util.Arrays; public class Main { public static void main(String[] args) { Scanner scanner = new Scanner(System.in); int n = scanner.nextInt(); int[] arr = new int[n]; for (int i = 0; i < n; i++) { arr[i] = scanner.nextInt(); } int[][][] dp = new int[n][n][n]; for (int i = 0; i < n - 1; i++) { dp[i][i + 1][i] = arr[i] * arr[i + 1]; dp[i][i + 1][i + 1] = dp[i][i + 1][i]; } for (int k = 2; k < n; k++) { for (int i = 0; i < n - k; i++) { for (int m = i; m <= i + k; m++) { int left = i == m ? 0 : dp[i][m - 1][i] + arr[i] * arr[m]; for (int l = i + 1; l < m; l++) { left = Math.min(left, dp[i][m - 1][l] + arr[l] * arr[m]); } int right = m == i + k ? 0 : dp[m + 1][i + k][i + k] + arr[i + k] * arr[m]; for (int r = m + 1; r < i + k; r++) { right = Math.min(right, dp[m + 1][i + k][r] + arr[r] * arr[m]); } dp[i][i + k][m] = left + right; } } } int res = dp[0][n - 1][0]; for (int i = 1; i < n; i++) { res = Math.min(res, dp[0][n - 1][i]); } System.out.println(res); } }
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; } })
import java.util.*;
public class Main {
static int n;
static int[] array;
static int[][][] memo;
public static void main(String[] args){
Scanner sc=new Scanner(System.in);
n =sc.nextInt();
memo=new int[n+1][n+1][n+1];
//数组用来储存树
array =new int[n+1];
for(int i=1;i<=n;i++){
array[i]=sc.nextInt();
}
//初始化记忆集,方便后面查看从i到j,以k为节点的树是否被遍历过
for (int i = 0; i < n + 1; i++) {
for (int j = 0; j < n + 1; j++) {
for (int k = 0; k < n + 1; k++) {
memo[i][j][k]=-1;
}
}
}
//定义函数,返回值为是以root为根节点,从数组第start到end个数作为其中一颗子树的最小开销,
//这个定义很重要,方便后续遍历,我们要求的就是dfs(1,array.length-1,0),为什么是0,因为可以假设
//有个值为0的root,并且0×任何数都得零,不影响最终结果,即使你子树中的根是什么值都和我无关
int res=dfs(1,array.length-1,0);
System.out.println(res);
}
public static int dfs(int start,int end,int root){
if(start>end){
return 0;
}
//首先查看记忆集里有没有之前遍历过的最优子树,有就返回
if (memo[start][end][root]!=-1){
return memo[start][end][root];
}
//没有就开始深度遍历,从start到end一个个作为根算出哪个作为根结果是最小的
int min =Integer.MAX_VALUE;
for(int i=start;i<=end;i++){
//根据此函数定义可以得出左子树的最优二叉树总开销
int left=dfs(start,i-1,i);
//同理可得右子树的总开销
int right=dfs(i+1,end,i);
//最后就是左子树+右子树+当前根*父根,这也是为什么一开始父根设为0的原因。我们要求最小值,就要遍历所有当前根
min=Math.min(min,left+right+array[root]*array[i]);
}
//最后把结果存到记忆集中,避免重复遍历
memo[start][end][root]=min;
return min;
}
}
import java.util.*; public class Main { public static void main(String[] args) { Scanner sc = new Scanner(System.in); while (sc.hasNext()) { int n = sc.nextInt(); int[] nums = new int[n + 1]; for (int i = 0; i < n; i++) { nums[i] = sc.nextInt(); } Main main = new Main(); int ans = Integer.MAX_VALUE; int[][][] memo = new int[n + 1][n + 1][n + 1]; for (int i = 0; i < n; i++) { ans = Math.min(ans,main.dfs(nums,0,i - 1,i,memo) + main.dfs(nums,i + 1,n - 1,i,memo)); } System.out.println(ans); } } int dfs(int[] nums, int l, int r, int father, int[][][] memo) { if (l > r) return 0; if (l == r) return nums[l] * nums[father]; if (memo[l][r][father] != 0) return memo[l][r][father]; int res = Integer.MAX_VALUE; for (int i = l; i <= r; i++) { int left = dfs(nums, l, i - 1, i, memo); int right = dfs(nums, i + 1, r, i, memo); res = Math.min(res, left + right + nums[i] * nums[father]); } memo[l][r][father] = res; return res; } }
我完全翻译的楼上的代码, 但是过不了!! 超时了, 是python的问题吗
N = 6 w = [0]*N f = [[[-1 for _ in range(N)] for _ in range(N)] for _ in range(N)] def dp(l, r, p): if l>r: return 0 if f[l][r][p] != -1: return f[l][r][p] ret = float('inf') for i in range(l, r+1): left = dp(l, i-1, i) right = dp(i+1, r, i) ret = min(ret, left+right+w[i]*w[p]) f[l][r][p] = ret return ret if __name__ == '__main__': n = int(input()) tmp = list(map(int, input().split(" "))) for i in range(1, n+1): w[i] = tmp[i-1] tmp = dp(1, n, 0) print(tmp)
n = int(input()) l = list(map(int, input().split(' '))) dp = [[[0]*n for _ in range(n)] for _ in range(n)] for jiange in range(1, n): for i in range(0, n-jiange): j = i + jiange for k in range(i, i+jiange+1): if jiange == 1: dp[i][j][k] = l[i]*l[j] else: if k == i: dp[i][j][k] = min([dp[k+1][j][q]+l[q]*l[k] for q in range(k+1, j+1)]) elif k == j: dp[i][j][k] = min([dp[i][k-1][p]+l[p]*l[k] for p in range(i, k)]) else: aa = min([dp[i][k-1][p]+l[p]*l[k] for p in range(i, k)]) bb = min([dp[k+1][j][q]+l[q]*l[k] for q in range(k+1, j+1)]) dp[i][j][k] = aa + bb print(min(dp[0][n-1]))
import java.util.Scanner; // 注意类名必须为 Main, 不要有任何 package xxx 信息 public class Main { public static void main(String[] args) { Scanner in = new Scanner(System.in); int n = in.nextInt(); int[] a = new int[n + 2]; for (int i = 1; i <= n; i++) { a[i] = in.nextInt(); } int[][][] f = new int[n + 2][n + 2][2]; for (int i = n; i >= 1; i--) { f[i][i][0] = a[i] * a[i + 1]; f[i][i][1] = a[i] * a[i - 1]; for (int j = i + 1; j <= n; j++) { f[i][j][0] = Integer.MAX_VALUE; f[i][j][1] = Integer.MAX_VALUE; for (int k = i; k <= j; k++) { f[i][j][0] = Math.min(f[i][j][0], a[k] * a[j + 1] + f[i][k - 1][0] + f[k + 1][j][1]); f[i][j][1] = Math.min(f[i][j][1], a[k] * a[i - 1] + f[i][k - 1][0] + f[k + 1][j][1]); } } } System.out.println(f[1][n][0]); } }
import java.util.*; // 注意类名必须为 Main, 不要有任何 package xxx 信息 public class Main { public static void main(String[] args) { Scanner in = new Scanner(System.in); int n = in.nextInt(); int[] nums = new int[n]; for (int i = 0; i < n; i++) { nums[i] = in.nextInt(); } int[][][] dp = new int[n + 1][n + 1][n + 1]; System.out.println(cost(nums, dp)); } public static int cost(int[] nums, int[][][] dp) { int n = nums.length; if (n == 1) return 0; if (n == 2) return nums[0] * nums[1]; int ans = Integer.MAX_VALUE; for (int i = 0; i < n; i++) { // System.out.println(nums[i]); ans = Math.min(ans, bt(nums, 0, i, i, dp) + bt(nums, i + 1, n, i, dp)); } return ans; } public static int bt(int[] nums, int l, int r, int root, int[][][] dp) { if (l == r) return 0; if (r == l + 1) { if (dp[l][r][root] == 0) dp[l][r][root] = nums[root] * nums[l]; return dp[l][r][root]; } if (r == l + 2) { if (dp[l][r][root] == 0) dp[l][r][root] = nums[l] * nums[l + 1] + Math.min( nums[l], nums[l + 1]) * nums[root]; return dp[l][r][root]; } if (dp[l][r][root] != 0) return dp[l][r][root]; int ans = Integer.MAX_VALUE; for (int i = l; i < r; i++) { if (dp[l][i][i] == 0) dp[l][i][i] = bt(nums, l, i, i, dp); if (dp[i + 1][r][i] == 0) dp[i + 1][r][i] = bt(nums, i + 1, r, i, dp); ans = Math.min(ans, dp[l][i][i] + dp[i + 1][r][i] + nums[i] * nums[root]); } dp[l][r][root] = ans; return ans; } }
#include <bits/stdc++.h> using namespace std; const int N = 3e2+5; int n,m,x,y; int a[N], dp[N][N][N]; int dfs(int l,int r, int fa){ if(l > r)return 0; if(dp[l][r][fa] != -1)return dp[l][r][fa]; int ans = 1e9; for(int i = l; i <= r; i++){ int left = dfs(l, i-1, i); int right = dfs(i+1, r, i); ans = min(ans, left + right + a[i] * a[fa]); } dp[l][r][fa] = ans; return ans; } int main(){ cin>>n; for(int i = 1; i <= n; i++){ cin>>a[i]; } memset(dp, -1, sizeof(dp)); dfs(1,n,0); cout<<dp[1][n][0]<<'\n'; return 0; }
import java.io.*; import java.util.*; public class Main { static String[] tree; static int[][][] dp; public static void main(String[] args) throws IOException { BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out)); int size = Integer.parseInt(br.readLine().trim()); tree = br.readLine().trim().split(" "); int min = Integer.MAX_VALUE; dp = new int[size][size][size]; for(int i = 0; i < size; i++){ for(int j = 0; j < size; j++) for(int k = 0; k < size; k++) dp[i][j][k] = Integer.MAX_VALUE; } for (int i = 0; i < size; i++) { int leftTree = build(0,i-1,i); int rightTree = build(i+1, size-1,i); min = Math.min(min, leftTree + rightTree); } bw.write(min+"\n"); bw.flush(); } public static int build(int left,int right,int parent){ if (left > right){ return 0; } if (dp[left][right][parent] != Integer.MAX_VALUE){ return dp[left][right][parent]; } for (int i = left; i <= right; i++) { int leftTree = build(left,i-1,i); int rightTree = build(i+1, right,i); dp[left][right][parent] = Math.min(dp[left][right][parent], Integer.parseInt(tree[parent]) * Integer.parseInt(tree[i]) + leftTree + rightTree); } return dp[left][right][parent]; } }
import java.util.*; public class Main{ public static void main(String args[]){ Scanner sc=new Scanner(System.in); int n=sc.nextInt(); int arr[]=new int[n]; for(int i=0;i<n;i++){ arr[i]=sc.nextInt(); } int dp[][][]=new int[n][n][n]; for(int i=1;i<=n;i++){ //区间长度 for(int j=0;j<=n-i;j++){ //区间起始点 for(int k=j;k<j+i;k++){ //分割点 int lm=Integer.MAX_VALUE,rm=Integer.MAX_VALUE,max=Integer.MAX_VALUE; for(int m=j;m<k;m++){ lm=Math.min(lm,dp[j][k-1][m]+arr[k]*arr[m]); } for(int f=k+1;f<j+i;f++){ rm=Math.min(rm,dp[k+1][j+i-1][f]+arr[k]*arr[f]); } if(lm==max&&rm==max){ dp[j][j+i-1][k]=0; } else if(lm==max){ dp[j][j+i-1][k]=rm; } else if(rm==max){ dp[j][j+i-1][k]=lm; } else{ dp[j][j+i-1][k]=lm+rm; } } } } int ans=Integer.MAX_VALUE; for(int i=0;i<n;i++){ ans=Math.min(ans,dp[0][n-1][i]); } System.out.println(ans); } }
#include<iostream> #include<fstream> #include<vector> #include<unordered_map> #include<unordered_set> #include<set> #include<map> #include<set> #include<queue> #include<stack> #include<deque> #include<cmath> #include<algorithm> #include<string> #include<cstring> using namespace std; int dp[310][310][310]; int dfs(vector<int>&res,int pos,int l,int r) { if(l>r) return 0; if(dp[pos][l][r]!=-1) return dp[pos][l][r]; int ans=pow(10,9); for(int i=l;i<=r;i++) { ans=min(ans,res[pos]*res[i]+dfs(res,i,l,i-1)+dfs(res,i,i+1,r)); } dp[pos][l][r]=ans; return ans; } int main() { memset(dp,-1,sizeof dp); int n;cin>>n; vector<int>res(n); for(int i=0;i<n;i++) cin>>res[i]; int ans=pow(10,9); for(int i=0;i<n;i++) { ans=min(ans,dfs(res,i,0,i-1)+dfs(res,i,i+1,n-1)); } cout<<ans; return 0; }
import java.util.*; import java.io.*; public class Main{ public static Info[][] dp; public static void main(String[] args) throws IOException{ BufferedReader br=new BufferedReader(new InputStreamReader(System.in)); int cnt=Integer.parseInt(br.readLine()); int[] nums=new int[cnt]; String[] temp=br.readLine().split(" "); for(int i=0;i<cnt;i++) nums[i]=Integer.parseInt(temp[i]); dp=new Info[cnt][cnt]; List<int[]> l=process(nums,0,cnt-1).res; int res=Integer.MAX_VALUE; for(int[] cur:l){ res=Math.min(res,cur[0]); } System.out.print(res); } public static Info process(int[] nums,int left,int right){ if(left>right) return null; List<int[]> l=new ArrayList<>(); for(int i=left;i<=right;i++){ int mul1=0; Info leftInfo; Info rightInfo; if(i-1<0||dp[left][i-1]==null) leftInfo=process(nums,left,i-1); else leftInfo=dp[left][i-1]; if(i+1>=nums.length||dp[i+1][right]==null) rightInfo=process(nums,i+1,right); else rightInfo=dp[i+1][right]; if(leftInfo!=null){ int mul2=Integer.MAX_VALUE; for(int[] cur:leftInfo.res){ mul2=Math.min(mul2,cur[0]+nums[cur[1]]*nums[i]); } mul1+=mul2; } if(rightInfo!=null){ int mul2=Integer.MAX_VALUE; for(int[] cur:rightInfo.res){ mul2=Math.min(mul2,cur[0]+nums[cur[1]]*nums[i]); } mul1+=mul2; } l.add(new int[]{mul1,i}); } Info result=new Info(l); dp[left][right]=result; return result; } } class Info{ List<int[]> res; public Info(List<int[]> res){ this.res=res; } }