1 #include <iostream> 2 #include <algorithm> 3 #include <list> 4 #include <vector> 5 6 using namespace std; 7 8 double e[10][10];//e[i][j]表示在k[i-1]和k[j+1]之间的关键字(全开区间)作为一颗有根树的最小搜索代价 9 double w[10][10];//w[i][j]表示在k[i-1]和k[j+1]之间的关键字(全开区间)的概率之和 10 double optimal_bst(double *p, double *q, const int n) {//n为关键字数量,假装n小于9,(逃 11 for (int i = 1;i <= n + 1;i++) 12 w[i][i - 1] = q[i - 1], e[i][i - 1] = q[i - 1]; 13 //e[1][n] 14 //状态转移方程:e[i][j]=e[i][r-1]+p[r]+e[r+1][j]+w[i][r-1]+w[r+1][j],其中两个w为区间内点下降获得的代价 15 //方程可转化为:e[i][j]=e[i][r-1]+e[r+1][j]+w[i][j] 16 for(int l=1;l<=n;l++) 17 for (int beg = 1;beg <= n - l + 1;beg++) { 18 int end = beg + l - 1; 19 w[beg][end] = w[beg][end - 1] + p[end] + q[end]; 20 e[beg][end] = INT_MAX; 21 for (int root = beg;root <= end;root++) 22 e[beg][end] = min(e[beg][end], e[beg][root - 1] + e[root + 1][end] + w[beg][end]); 23 } 24 cout << e[1][n] << endl; 25 return e[1][n]; 26 }
感觉这个比较妙的主要是状态的定义,e[i][j]表示在k[i-1]和k[j+1]之间的关键字(全开区间)作为一颗有根树的最小搜索代价,w[i][j]表示在k[i-1]和k[j+1]之间的关键字(全开区间)的概率之和,同时也把e[i][i-1]和w[i][i-1]的情况包括进去了,即伪节点的概率,除了注意一些边界问题,难度还行。以上,跑过书里的一个例子,答案2.75
1 int main(void) { 2 double p[10] = { 0.0,0.15,0.10,0.05,0.10,0.20 }; 3 double q[10] = { 0.05,0.10,0.05,0.05,0.05,0.10 }; 4 optimal_bst(p, q, 5); 5 6 return 0; 7 }