原问题是给出各个节点和各个节点的被查找概率,然后构造一棵各个节点平均被查找比较次数最小的树,则该问题可以用动态规划来解决
#include<bits/stdc++.h>
using namespace std;
const int M = 100;
double C[M][M], W[M][M], p[M], q[M];
int S[M][M];
int n, i, j, k;
void Optimal_BST()
{
for (i=1;i<=n;i++)
{
C[i][i - 1] = 0.0;
W[i][i - 1] = q[i - 1];
}
for (int t=1;t<=n;t++)
{
for (i = 1; i <= n - t + 1; i++)
{
j = i + t - 1;
W[i][j] = W[i][j - 1] + p[j] + q[j];
C[i][j] = C[i][i - 1] + C[i + 1][j];
S[i][j] = i;
// 选取i+1到j之间的某个下标的关键字作为i到j的根,如果组成的期望值最小
// 则k为i到j的根结点
for (k = i + 1; k < j; k++)
{
double tmp = C[i][k - 1] + C[k + 1][j];
if (tmp<C[i][j] && fabs(tmp - C[i][j])>1E-6)
{
C[i][j] = tmp;
S[i][j] = k; // 记录i到j结点的树根
}
}
C[i][j] += W[i][j];
}
}
}
void Construct_Optimal_BST(int i,int j,bool flag)
{
if (flag == 0)
{
cout << "S" << S[i][j] << "是根" << endl;
flag = 1;
}
int k = S[i][j];
// 如果左子树是叶子
if (k - 1 < i)
{
cout << "e" << k - 1 << "is the left child of " << "S" << k << endl;
}
else
{
cout << "S" << S[i][k - 1] << " is the left child of" << "S" << k << endl;
Construct_Optimal_BST(i, k - 1, 1);
}
// 如果右子树是叶子
if (k>=j)
{
cout << "e" << j << " is the right child of " << "S" << k << endl;
}
else
{
cout << "S" << S[k + 1][j] << " is the right child of " << "S" << k << endl;
Construct_Optimal_BST(k + 1, j, 1);
}
}
int main()
{
cout << "请输入关键字的个数:" << endl;
cin >> n;
cout << "请依次输入关键字的频率:" << endl;
for (i = 1; i <= n; i++)
{
cin >> p[i];
}
cout << "请依次输入每个虚结点的搜索频率:" << endl;
for (i = 0; i <= n; i++)
{
cin >> q[i];
}
Optimal_BST();
cout << "最小的搜索成本是" << C[1][n] << endl;
cout << "最优二叉搜索树为:" << endl;
Construct_Optimal_BST(1, n, 0);
system("pause");
return 0;
}