最佳二进制搜索树错误输出

时间:2015-03-12 12:52:20

标签: c algorithm dynamic-programming

我正在研究一个问题,它通过尽可能最好地排列二进制搜​​索树来计算所需的最小遍历次数。我确实遇到了一个在线的解决方案,我已经理解了,但我手工完成了一些样本输入的计算,但是我没有得到正确的结果。

以下是代码

#include <stdio.h>
#include <limits.h>

// A utility function to get sum of array elements freq[i] to freq[j]
int sum(int freq[], int i, int j);

/* A Dynamic Programming based function that calculates minimum cost of
   a Binary Search Tree. */
int optimalSearchTree(int keys[], int freq[], int n)
{
    /* Create an auxiliary 2D matrix to store results of subproblems */
    int cost[n][n];

    /* cost[i][j] = Optimal cost of binary search tree that can be
       formed from keys[i] to keys[j].
       cost[0][n-1] will store the resultant cost */

    // For a single key, cost is equal to frequency of the key
    for (int i = 0; i < n; i++)
        cost[i][i] = freq[i];

    // Now we need to consider chains of length 2, 3, ... .
    // L is chain length.
    for (int L=2; L<=n; L++)
    {
        // i is row number in cost[][]
        for (int i=0; i<=n-L+1; i++)
        {
            // Get column number j from row number i and chain length L
            int j = i+L-1;
            cost[i][j] = INT_MAX;

            // Try making all keys in interval keys[i..j] as root
            for (int r=i; r<=j; r++)
            {
               // c = cost when keys[r] becomes root of this subtree
               int c = ((r > i)? cost[i][r-1]:0) + 
                       ((r < j)? cost[r+1][j]:0) + 
                       sum(freq, i, j);
               if (c < cost[i][j])
                  cost[i][j] = c;
            }
        }
    }
    return cost[0][n-1];
}

// A utility function to get sum of array elements freq[i] to freq[j]
int sum(int freq[], int i, int j)
{
    int s = 0;
    for (int k = i; k <=j; k++)
       s += freq[k];
    return s;
}

// Driver program to test above functions
int main()
{
    int keys[] = {10, 12, 20};
    int freq[] = {34, 8, 50};
    int n = sizeof(keys)/sizeof(keys[0]);
    printf("Cost of Optimal BST is %d ", optimalSearchTree(keys, freq, n));
    return 0;
}

例如输入     int keys [] = {1,2,3};     int freq [] = {10,3,1};

  

我应该得到18但我得到19

对于此输入  int keys [] = {1,2,3,4}; int freq [] = {5,4,1,200};

  

我应该得到225我得到226

对于此输入  int keys [] = {1,2,3,4,5,6}; int freq [] = {33,1,409,2,1,34};

  

我应该得到997但我得到556

对于此输入  int keys [] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20}; int freq [] = {5,5,5,5,5,5,5,5,5,5,167,5,5,5,5,5,5,5,5,5};

  

我应该得到789但我得到532

有什么问题?

1 个答案:

答案 0 :(得分:2)

你错误的预期结果。拿第一个例子,使用密钥{1, 2, 3}和频率{10, 3, 1};最优二叉搜索树是:

  1 (10)
   \
    2 (3)
     \
      3 (1)

(括号中给出的频率)。该函数返回用于搜索树总和(频率)次数的预期成本,如通过访问的节点数量所测量的,它是(10 * 1) + (3 * 2) + (1 * 3) = 19。每次搜索密钥1都只遍历根节点。每次搜索密钥2都会遍历根节点,在其子节点中查找目标密钥,总共遍历两个节点。同样,每次搜索密钥3都会遍历三个节点。

根据访问的节点来衡量成本是有意义的,因为必须对每个访问节点的密钥进行比较,但您也可以根据遍历的边缘来衡量成本。但是,如果计算传入根的边,表示主机程序指向树的指针,结果是相同的。在这种情况下,每个节点访问都涉及遍历该节点的传入边缘,从而在节点访问或边缘遍历方面消除计算成本之间的任何区别。

使用密钥{1,2,3,4}和频率{5,4,1,200},最佳二叉搜索树是

    4 (200)
   /
  1 (5)
   \
    2 (4)
     \
      3 (1)

费用为(200 * 1) + (5 * 2) + (4 * 3) + (1 * 4) = 226

使用密钥{1,2,3,4,5,6}和频次{33,1,409,2,1,34}

            3 (409)
          /     \
         /       \
        1 (33)    6 (34)
         \       /
          2 (1)  4 (2)
                  \
                   5(1)

费用(409 * 1) + ((33 + 34) * 2) + ((1 + 2) * 3) + (1 * 4) = 556

程序会在每种情况下返回正确的结果。

我把这个20键的例子作为练习留给你。对于该情况,存在多个最佳搜索树,但是所有都具有532,如程序所给出的。