写一个C语言程序实现给定标识符集(a 1 , a 2 , …a n ),这些字符的下标从1开始按自然序编号,p i 是对a i 成功检索的概率, q i 是不成功检索的概率, 且∑ (1<=i<=n) p i +∑ (0<=i<=n) q i =1,问:它的最优二分检索树是怎样的? 输入格式: 第1行是n,表示字符个数; 第2行是这n个字符的成功检索概率p i , 0<p i <1; 第3行是失败检索概率q i ,0<q i <1,且∑ (1<=i<=n) p i +∑ (0<=i<=n) q i =1。 输出格式: 最优二分检索树先根遍历时得到的字符编号序列。 输入样例1: 4 0.1875 0.1875 0.0625 0.0625 0.125 0.1875 0.0625 0.0625 0.0625 输出样例1: 2 1 3 4
时间: 2024-03-13 16:47:16 浏览: 75
```c
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#define MAXN 1000
double p[MAXN + 1], q[MAXN + 1];
double w[MAXN + 2][MAXN + 1]; // w[i][j]表示从i到j的权值和
double e[MAXN + 2][MAXN + 1]; // e[i][j]表示最优的二叉树的期望搜索代价
int root[MAXN + 1][MAXN + 1]; // root[i][j]表示从i到j的最优根结点
void optimal_bst(int n)
{
for (int i = 1; i <= n + 1; i++) {
w[i][i - 1] = q[i - 1];
e[i][i - 1] = q[i - 1];
}
for (int len = 1; len <= n; len++) {
for (int i = 1; i <= n - len + 1; i++) {
int j = i + len - 1;
w[i][j] = w[i][j - 1] + p[j] + q[j];
e[i][j] = INT_MAX; // 初始化为最大值
for (int k = i; k <= j; k++) {
double tmp = e[i][k - 1] + e[k + 1][j] + w[i][j];
if (tmp < e[i][j]) {
e[i][j] = tmp;
root[i][j] = k;
}
}
}
}
}
void preorder(int i, int j)
{
if (i <= j) {
printf("%d ", root[i][j]);
preorder(i, root[i][j] - 1);
preorder(root[i][j] + 1, j);
}
}
int main()
{
int n;
scanf("%d", &n);
for (int i = 1; i <= n; i++) {
scanf("%lf", &p[i]);
}
for (int i = 0; i <= n; i++) {
scanf("%lf", &q[i]);
}
optimal_bst(n);
printf("最优二分检索树先根遍历时得到的字符编号序列:");
preorder(1, n);
printf("\n");
return 0;
}
```
阅读全文