DP24 最优BST Optimal Binary Search Tree @geeksforgeeks

Given a sorted array keys[0.. n-1] of search keys and an array freq[0.. n-1] of frequency counts, wherefreq[i] is the number of searches to keys[i]. Construct a binary search tree of all keys such that the total cost of all the searches is as small as possible.

Let us first define the cost of a BST. The cost of a BST node is level of that node multiplied by its frequency. Level of root is 1.

Example 1
Input:  keys[] = {10, 12}, freq[] = {34, 50}
There can be following two possible BSTs 
        10                       12
          \                     / 
           12                 10
          I                     II
Frequency of searches of 10 and 12 are 34 and 50 respectively.
The cost of tree I is 34*1 + 50*2 = 134
The cost of tree II is 50*1 + 34*2 = 118 

Example 2
Input:  keys[] = {10, 12, 20}, freq[] = {34, 8, 50}
There can be following possible BSTs
    10                12                 20         10              20
      \             /    \              /             \            /
      12          10     20           12               20         10  
        \                            /                 /           \
         20                        10                12             12  
     I               II             III             IV             V
Among all possible BSTs, cost of the fifth BST is minimum.  
Cost of the fifth BST is 1*50 + 2*34 + 3*8 = 142

1) Optimal Substructure:
The optimal cost for freq[i..j] can be recursively calculated using following formula.
optCost(i, j) = \sum\limits_{k=i}^j freq[k] + \min\limits_{r=i}^j  [ optCost(i, r-1) + optCost(r+1, j) ]

We need to calculate optCost(0, n-1) to find the result.

The idea of above formula is simple, we one by one try all nodes as root (r varies from i to j in second term). When we make rth node as root, we recursively calculate optimal cost from i to r-1 and r+1 to j.
We add sum of frequencies from i to j (see first term in the above formula), this is added because every search will go through root and one comparison will be done for every search.

2) Overlapping Subproblems
Following is recursive implementation that simply follows the recursive structure mentioned above.


Dynamic Programming Solution
Following is C/C++ implementation for optimal BST problem using Dynamic Programming. We use an auxiliary array cost[n][n] to store the solutions of subproblems. cost[0][n-1] will hold the final result. The challenge in implementation is, all diagonal values must be filled first, then the values which lie on the line just above the diagonal. In other words, we must first fill all cost[i][i] values, then all cost[i][i+1] values, then all cost[i][i+2] values. So how to fill the 2D array in such manner> The idea used in the implementation is same as Matrix Chain Multiplication problem, we use a variable ‘L’ for chain length and increment ‘L’, one by one. We calculate column number ‘j’ using the values of ‘i’ and ‘L’.


package DP;

public class OptimalBinarySearchTree {

	public static void main(String[] args) {
		int[] keys = {10,12,20};
		int[] freq = {34,8,50};
		int n = keys.length;
		System.out.println("Cost of Optimal BST is " + optimalSearchTreeRec(keys, freq, n));
		System.out.println("Cost of Optimal BST is " + optimalSearchTreeDP(keys, freq, n));
	}
	
	public static int optCost(int[] freq, int begin, int end){
		if(end < begin){		// If there are no elements in this subarray
			return 0;
		}
		if(begin == end){		// If there is one element in this subarray
			return freq[begin];
		}
		
		// 每往下走一步,都要加上从begin到end的freq和
		int fsum = sum(freq, begin, end);	// Get sum of freq[i], freq[i+1], ... freq[j]
		int min = Integer.MAX_VALUE;		// Initialize minimum value
		
		// One by one consider all elements as root and recursively find cost
		// of the BST, compare the cost with min and update min if needed
		for(int r=begin; r<=end; r++){
			int cost = optCost(freq, begin, r-1) + optCost(freq, r+1, end);
			min = Math.min(min, cost);
		}
		
		return min + fsum;		// Return minimum value
	}
	
	// A utility function to get sum of array elements freq[i] to freq[j]
	public static int sum(int[] freq, int begin, int end){
		int sum = 0;
		for(int i=begin; i<=end; i++){
			sum += freq[i];
		}
		return sum;
	}
	
	// The main function that calculates minimum cost of a Binary Search Tree.
	// It mainly uses optCost() to find the optimal cost.
	public static int optimalSearchTreeRec(int[] keys, int[] freq, int n){
		// Here array keys[] is assumed to be sorted in increasing order.
	     // If keys[] is not sorted, then add code to sort keys, and rearrange
	     // freq[] accordingly.
		return optCost(freq, 0, n-1);
	}

	/* A Dynamic Programming based function that calculates minimum cost of
	   a Binary Search Tree. */
	public static int optimalSearchTreeDP(int[] keys, int[] freq, int n){
		int[][] cost = new int[n][n];		 /* Create an auxiliary 2D matrix to store results of subproblems */
		
		/* 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(int i=0; i<n; i++){
			cost[i][i] = freq[i];	// 只有一个元素时,cost为freq,就是把那个元素作为root
		}
		
		// Now we need to consider chains of length 2, 3, ... .
		for(int L=2; L<=n; L++){		// L is chain length.
			for(int begin=0; begin<n-L+1; begin++){		// begin: begin index in keys
				int end = begin+L-1;		// end: end index in keys
				cost[begin][end] = Integer.MAX_VALUE;
				
				// Try making all keys in interval keys[begin..end] as root
				for(int r=begin; r<=end; r++){
					// c = cost when keys[r] becomes root of this subtree
					int c = (r>begin ? cost[begin][r-1] : 0) + (r<end ? cost[r+1][end] : 0) + sum(freq, begin, end);
					cost[begin][end] = Math.min(cost[begin][end], c);
				}
			}
		}
		
		return cost[0][n-1];
	}
	
	
}



http://www.geeksforgeeks.org/dynamic-programming-set-24-optimal-binary-search-tree/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值