标签:算法
此题是算法导论贪心算法的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 = values[i]; activities.push_back(tmp); } int profit = getMostProfit(activities); cout << "mostProfit is "<<profit << endl; }
参考:《算法导论》
标签:算法
原文地址:http://blog.csdn.net/chenlei0630/article/details/40862499