算法导论 习题 16.1-5

16.1-5

给定n个活动的开始时间和结束时间表,及每个活动的收益表,求对这些活动的一个组织使收益最大化。


这问题其实CLRS正文介绍贪心算法时用到的 活动选择问题 的泛化;即能用贪心算法解决的活动选择是该问题的一个特例:收益都是1。

而这里,收益是各不相同的。于是直观地看,需要用到dp解决。

而因为活动之间存在兼容问题:j的开始时间有可能与 i 的结束时间或者开始时间冲突,所以对活动j,必须比较选择和不选择带来的收益。

可以定义一个数组,描述每一个活动 与 其他活动的兼容情况:compatible[ j ] = i 表示 与j 兼容的最大的 i,即 所有 finish [ i ] <= start [ j ]中,i的最大值。

于是 选择j的收益 = j的兼容活动的收益 + j本身的价值,而不选择j的收益 = j前一个活动的兼容活动集合带来的收益。

即 optimal [ i ] = max { value[i] + optimal [compatible [i] ] , optimal [ i-1 ] }   

========================

代码如下:

package com.cupid.algorithm.dp;

public class ActivitySelection {
	
	public static void ConstructSolution(int[] opt,int[] compatible,int[] v,int number){
		if(number == 0){
			System.out.println("done");
		}else if(v[number] + opt[compatible[number]] > opt[number-1]){
			System.out.println(v[number] + " by "+ " Activity " + number);
			ConstructSolution(opt, compatible, v, compatible[number]);
		}else{
			ConstructSolution(opt, compatible, v, number-1);
		}
	}
	
	// CLRS 16.1-5
	public static int ActivitySelectionMaximizingValue(int[] start,int[] finish,int[] v,int n,int[] opt){
		int[] compatible = new int[n+1];
		// Find out all compatible activities for each activity,
		// runs in O(N*lgN)
		for(int i=1;i<compatible.length;i++){
			compatible[i] = binarySearchCompatible(finish,start[i]);
		}

		for(int i=1;i<opt.length;i++){
			opt[i] = 0;
			if(opt[compatible[i]]+v[i] > opt[i-1]){
				opt[i] = opt[compatible[i]]+v[i];
			}else{
				opt[i] = opt[i-1];
			}
		}
		
		ConstructSolution(opt,compatible,v,n);
		
		return opt[n];
	}
	
	
	// Given activity j's start time and finish time table, 
	// do a binary search to find a compatible activity i with activity j, 
	// where i is the largest number <= j  
	private static int binarySearchCompatible(int[] finish,int startTime){
		int highestCompatible = 0;
		int low = 0;
		int high = finish.length-1;
		int mid = 0;
		// Do binary search
		while(low<=high){
			mid = (low+high)/2;
			// When low = high,
			// an exact finish time may or may not be found.
			// Assign value to highestCompatible accordingly.
			if(low==high){
				// e.g. find 15 between 14,16 and finish[mid] = 16.
				// In this case return index of 14
				if(startTime<finish[mid]){
					highestCompatible = mid-1;
				// e.g. find 15 between 14,16 and finish[mid] = 14.
				// In this case return index of 14
			    }else if(startTime>finish[mid]){
			    	highestCompatible = mid;
				}
			 }
			if(startTime<finish[mid]){
				 high = mid-1;
			}else if(startTime>finish[mid]){
				low = mid+1;
			}else{
				highestCompatible = mid;
				break;
			}
		}
		return highestCompatible;
	}
	
	public static void main(String[] args) {
		int[] start = new int[]{-1,1,3,0,5,3,5,6,8,8,2,12};
		 // If finish-time array is not in order, sort it in O(N*lgN)
		int[] finish = new int[]{0,4,5,6,7,9,9,10,11,12,14,16};
		// Different weights are given to different activities.
		int[] value = new int[]{0,3,2,4,8,2,5,6,5,7,4,5};
		int[] optimal = new int[start.length];
		optimal[0] = 0;
		int size = start.length-1;
		System.out.println("The maximum value is " + ActivitySelectionMaximizingValue(start, finish, value, size,optimal));
	}

}


====================

PS :标签上贪心只是与能用贪心解的权重为1的活动选择特例作比较。

参考:http://www.cs.princeton.edu/~wayne/cs423/lectures/dynamic-programming-4up.pdf

你可能感兴趣的:(算法导论 习题 16.1-5)