题意:
前提要了解什么是二叉查找树,然后再是最优二叉查找树。
最优二叉查找树是指,在二叉查找树的基础上,要求总的编码长度最小(类似huffman编码)。
思路:
看似十分复杂,其实我们抛开许多细节可以发现,作为根节点,其左右子树一定也是最优的。
基于这个思想,就可以很自然的想起区间动态规划,从小规模最优解逐渐扩大。
如果区间规模增大,则要选出一个新的根节点,而区间上除了根节点左右最优解要多加一个高度,于是有递推公式:
k1 = max(k - 1, i),k2 = min(k + 1, j); (i <= k <= j)
dp[i][j] = min(dp[i][j], dp[i][k1] + dp[k2][j] + sum[j] - sum[i-1] - a[k]);
前提条件是:a[]数组元素要保持递增/递减顺序
#include <cstdio> #include <cstdlib> #include <cstring> #include <climits> #define max(a,b) (((a) > (b)) ? (a) : (b)) #define min(a,b) (((a) < (b)) ? (a) : (b)) const int MAXN = 256; int dp[MAXN][MAXN]; int a[MAXN], sum[MAXN]; int main() { int n; while (scanf("%d", &n) != EOF) { for (int i = 1; i <= n; ++i) scanf("%d", &a[i]); sum[0] = 0; for (int i = 1; i <= n; ++i) dp[i][i] = 0, sum[i] = sum[i-1] + a[i]; for (int p = 2; p <= n; ++p) { for (int i = 1, j = p; j <= n; ++i, ++j) { dp[i][j] = INT_MAX; for (int k = i; k <= j; ++k) { int k1 = max(k - 1, i); int k2 = min(k + 1, j); dp[i][j] = min(dp[i][j], dp[i][k1] + dp[k2][j] + sum[j] - sum[i-1] - a[k]); } } } printf("%d\n", dp[1][n]); } return 0; }