首页 > 代码库 > 活动安排问题

活动安排问题

此题是算法导论贪心算法的16.1-5题。



问题描述:

考虑一个活动选择问题的一个变形:每个活动ai除了开始和结束时间外,还有一个值vi。目标不再是求规模最大的兼容活动子集,而是求值之和最大的兼容活动子集。也就是说,选择一个兼容活动子集A,是的vk(k属于A)之和最大化。设计一个多项式时间的算法求解此问题。


思路:

此题是活动安排问题的一个变形。最优化目标不再是最大兼容活动子集,所以不能用常规的活动安排问题的贪心方案。

考虑这样一个问题,我们对与每个活动i,都可以考虑这个活动i是否被加入到最优活动子集中。所以opt[i]可以从这两中情况得来。

opt[i] = max(opt[i-1], opt(pre(i)+vi));

上述公式需要建立在活动已排序的基础上。活动按照结束时间升序排序。不选择第i个活动时,opt[i] = opt[i-1]; 选择第i个活动时opt[i] = opt(pre(i) + vi); pre(i)表示i活动开始之前结束的活动。根据这个公式我们可以轻松的写出动态规划的代码。

该方法最坏情况下时间复杂度为O(n^2);最好情况下为O(n);


代码:

#include <iostream>  //c++
#include <algorithm>
#include <vector>

using namespace std;
typedef struct activity{
	int start;
	int end;
	int value;
}Activity;

bool myfunction (Activity a, Activity b) {
	return (a.end < b.end);
}

int getMostProfit(vector<Activity> activities){
	if(activities.size() == 0)
		return 0;

	sort(activities.begin(), activities.end(),myfunction);

	int opt[activities.size()];
	opt[0] = activities[0].value;
	for(int i = 1; i < activities.size(); i++){
		int j;
		for(j = i-1; j >=0; j--){
			if(activities[j].end <= activities[i].start)
				break;
		}
		if(j >=0)
			opt[i] = ((opt[i-1]>opt[j]+activities[i].value)?opt[i-1]:(opt[j]+activities[i].value));
		else opt[i] = ((opt[i-1]>activities[i].value)?opt[i-1]:activities[i].value);
	}
	for(int i = 0; i < activities.size(); i++)		cout << opt[i] << endl;
	return opt[activities.size()-1];
}



int main(){
	int starts[] = {1,3,0,5,3,5,6,8,8,2,12};
	int  ends[]  ={4,5,6,7,9,9,10,11,12,14,16};
	int  values[] = {1,2,4,6,4,2,3,3,4,1,3};

	vector<Activity> activities;
	for(int i = 0; i < 11 ; i++){
		Activity tmp;
		tmp.start = starts[i];
		tmp.end  = ends[i];
		tmp.value = http://www.mamicode.com/values[i];>

参考:《算法导论》

活动安排问题