题目描述
T 是由有序集合S = {X ,X ……, X ) (X <X ……,<X) 构成的二叉搜索树 在其中查找某个值
- X ∈ (Xi, Xi+1) 的概率为 ai
- X = Xi 的概率为bi
规定 x0 = -∞ , Xn+1 = +∞ ,
存取分布概率
- 称 (a0 , b1 ,a1 , ….. , bn , an ) 为集合S的存取概率分布

平均路长

- 当S确定时具有平均最小路长的T就是对应的最优二叉树
递归求解最优值
定义
- W[i]: a0 + b1 + a1 + ……. + bi + ai
- w[i][j] : a + bi + ai + ……. + bj + aj
- a[i] : (xi-1, xi) 的存取概率
- b[i] : xi 的存取概率
- root[i][j] : 当子树为T时的根节点
- m[i][j] :当子树为T是后的
基础解
代码
/*设 S={x1, x2, ···, xn} 是一个有序集合,且x1, x2, ···, xn表示有序集合的二叉搜索树利用二叉树的顶点存储有序集中的元素,而且具有性质:存储于每个顶点中的元素x 大于其左子树中任一个顶点中存储的元素,小于其右子树中任意顶点中存储的元素。最优二叉树就是平均路长最小的数*/#include<stdio.h>#include<stdlib.h>const int N = 100;double w[N][N];//w[i][j]=ai-1 + bi + .... + bj + ajdouble m[N][N];//m[i][j] = w[i][j]P(ij)int n;//元素个数double a[N];//失败概率double b[N];//失败概率int root[N][N];//当子树Tij 最优时候的根节点在S中的下标int q = 0;double W[N];//显示解的树形结构void showTree(int l,int r,int deep) {if (l > r) {for (int i = 0; i < deep; i++) {printf("-");}printf("q%d\n",q++);return;}for (int i = 0; i < deep; i++) {printf("-");}printf("%d\n",root[l][r]);showTree(l, root[l][r] - 1, deep + 1);showTree( root[l][r] + 1,r, deep + 1);}//计算 a[i-1] + b[i] + a[i] + ..... + b[j] + a[h]double getW(int i, int j) {return W[j] - W[i - 1] + a[i - 1];}int main() {//输入scanf("%d", &n);scanf("%lf", &a[0]);//输入a0W[0] = a[0];for (int i = 1; i <=n; i++) { // b1 , a1, ... bn , anscanf("%lf", &b[i]);scanf("%lf", &a[i]);W[i] = W[i - 1] + a[i] + b[i];//用来求解区间和}//初始化 当非叶节点个数为1时for (int i = 1; i <= n; i++) {w[i][i] = a[i - 1] + a[i] + b[i];m[i][i] = w[i][i];root[i][i] = i;}//动态规划for (int r = 2; r <= n; r++) {//子树非叶节点个数for (int i = 1; i <= n - r + 1; i++) {//子树起点int j = i + r - 1;//子树终点root[i][j] = i;m[i][j] = 0xFFFFFF;for (int k = i; k <= j; k++) {//轮流作为根节点if (m[i][j] > getW(i,j) + m[i][k - 1] + m[k + 1][j]) {root[i][j] = k;m[i][j] = getW(i, j) + m[i][k - 1] + m[k + 1][j];}}}}//输出最短平均路径m[1][n]printf("%.2lf\n", m[1][n]);//表达树showTree(1,n,1);return 0;}
- 输入样例
3
0.15 0.5 0.1 0.1 0.05 0.05 0.05
- 输出
1.50
-1
—q0
—2
—-q1
—-3
——q2
——q3

#include<stdio.h>#include<stdlib.h>const int N = 100;double w[N][N];//w[i][j]=ai-1 + bi + .... + bj + ajdouble m[N][N];//m[i][j] = w[i][j]P(ij)int n;//元素个数double a[N];//失败概率double b[N];//失败概率int root[N][N];//当子树Tij 最优时候的根节点在S中的下标int q = 0;double W[N];//用来区间求和 w[i][j] = a[i-1] + b[i] + a[i] + ..... + b[j] + a[h] = W[j] - W[i - 1] + a[i - 1]void showTree(int l,int r,int deep) {if (l > r) {for (int i = 0; i < deep; i++) {printf("-");}printf("q%d\n",q++);return;}for (int i = 0; i < deep; i++) {printf("-");}printf("%d\n",root[l][r]);showTree(l, root[l][r] - 1, deep + 1);showTree( root[l][r] + 1,r, deep + 1);}//计算 a[i-1] + b[i] + a[i] + ..... + b[j] + a[h]double getW(int i, int j) {return W[j] - W[i - 1] + a[i - 1];}int main() {//输入scanf("%d", &n);scanf("%lf", &a[0]);//输入a0W[0] = a[0];for (int i = 1; i <=n; i++) { // b1 , a1, ... bn , anscanf("%lf", &b[i]);scanf("%lf", &a[i]);W[i] = W[i - 1] + a[i] + b[i];}//查看输入printf("\n");printf("a : ");for (int i = 0; i <= n; i++) {printf("%.2lf ", a[i]);}printf("\n");printf("b : ");for (int i = 1; i <= n; i++) {printf("%.2lf ", b[i]);}printf("\n");//初始化for (int i = 1; i <= n; i++) {w[i][i] = a[i - 1] + a[i] + b[i];//m[i][i] = w[i][i];root[i][i] = i;}//动态规划for (int r = 2; r <= n; r++) {//子树非叶节点个数for (int i = 1; i <= n - r + 1; i++) {//子树起点int j = i + r - 1;//子树终点root[i][j] = i;m[i][j] = 0xFFFFFF;for (int k = i; k <= j; k++) {//轮流作为根节点if (m[i][j] > getW(i,j) + m[i][k - 1] + m[k + 1][j]) {root[i][j] = k;m[i][j] = getW(i, j) + m[i][k - 1] + m[k + 1][j];}}}}//输出最短平均路径m[1][n]printf("%.2lf\n", m[1][n]);//显示w 和 mfor (int i = 1; i <= n; i++) {for (int j = 1; j <= n; j++) {printf("%.2lf ", m[i][j]);}printf("\n");}printf("\n"); printf("\n");for (int i = 1; i <= n; i++) {for (int j = 1; j <= n; j++) {printf("%4.2lf ", getW(i,j));}printf("\n");}//表达树showTree(1,n,1);return 0;}
作业 :
- 1.设n=4,有序集为k1, k2, k3, k4,存取概率设b(1 : 4)=(3, 3, 1, 1)和a(0 : 4)=(2,3,1,1,1)写出构造最优二叉搜索树的过程。
输入 :
4 2 3 3 3 1 1 1 1 1
输出 :
注意:b,a都乘了16。



