greedy策略求解活动选择问题 ActivitySelectProblem

       活动选择问题:有N个活动,仅安排一个人去完成,求一个人在不限时的情况下最多能完成几个活动,要求:活动包含开始时间和结束时间,活动的时间点不能变,就是说到时了,到点的活动必须开始。

       这个问题为什么能够用greedy思想来求解,一个最直接的想法就是:活动已经按照时间点计划好了,我要尽可能完成多的活动,那么当前活动如果能尽快结束,我就能尽快接着去完成下一个活动,反过来如果当前正在完成的活动一直到其他活动都结束了,当前的活动才结束,那么最后我就只完成了一个活动。所以greedy策略就是每次选择下一个最早时间结束的活动去完成,那么如何每次都能选择除当前活动外剩余结束时间最早的活动呢,一个方法就是对所有活动按照最早结束时间进行排序。因此该题的解法核心实现首先在于对最早结束时间进行排序,然后依次选择符合条件(下一个活动的开始时间必须不小于当前活动的结束时间,因为只有一个人去完成)的最早结束时间的活动,并进行累加实现。不管该greedy是否能够得出最优解,但是从当前来看至少可以得到一个不错的解答。注:greedy注重于求解问题,而不是求解的效率,但是可以在greedy求解问题的时候,其中的某些步骤或环节可以采用效率较高的分治法进行求解,比如在对最早结束时间进行排序时,本文就采用了基于分治法的归并排序,这样实现对问题的高效求解。

        主体框架算法如下:

//***************************activity*****************************
int GreedyStrategy::activitySelectProblem(map<double, double> &activities)
{
	//仅对map迭代器指针进行排序,map<earily,later>
	map<double, double>::iterator iter = activities.begin();                   //本质上是赋值迭代器以头地址
	vector<map<double, double>::iterator> activitiesNumPtr;                       //然后将所有的指针放入vector中进行排序
	while (iter != activities.end())
	{
		activitiesNumPtr.push_back(iter);
		iter++;
	}

	mergeSortActivities(activitiesNumPtr, 0, activitiesNumPtr.size() - 1);           //已按照later从小到大排序,按照最早结束的最先安排

	//-----------选择和判断符合要求的最早结束的活动------------------------------------
	int number = 0;
	if (activitiesNumPtr.size())
	{
		number++;
	}

	for (int i = 0, j = 1; j < activitiesNumPtr.size();)                           //activitiesNumPtr是已经排序好的结束时间点
	{
		if (activitiesNumPtr[j]->first >= activitiesNumPtr[i]->second)
		{
			number++;
			i = j;
			j++;
		}
		else
		{
			j++;
		}
	}

	return number;
}

       以上需要注意的是,在使用greedy策略选择已排序活动时,使用i下标指向当前正在执行的活动,而j指向待选择的活动,如果j活动不满足条件,那么j++,直到j遍历完所有的活动为止。

       以下是活动的高效分治归并排序算法:


void GreedyStrategy::mergeSortActivities(vector<map<double, double>::iterator> &activitiesPtr, int low, int high)
{
	if (low < high)
	{
		int mid = (low + high) / 2;
		mergeSortActivities(activitiesPtr, low, mid);
		mergeSortActivities(activitiesPtr, mid + 1, high);
		conquerActivities(activitiesPtr, low, mid, high);
	}

}

void GreedyStrategy::conquerActivities(vector<map<double, double>::iterator> &activitiesPtr, int low, int mid, int high)
{
	int i = low;
	int j = mid + 1;
	vector<map<double, double>::iterator> num;
	while (i <= mid&&j <= high)
	{
		if (activitiesPtr[i]->second < activitiesPtr[j]->second)                                   // 编程原因:越早结束,则活动数越多
		{
			num.push_back(activitiesPtr[i]);
			i++;
		}
		else
		{
			num.push_back(activitiesPtr[j]);
			j++;
		}
	}

	while (i <= mid)
	{
		num.push_back(activitiesPtr[i]);
		i++;
	}

	while (j <= high)
	{
		num.push_back(activitiesPtr[j]);
		j++;
	}

	for (int i = low, k = 0; i <= high; i++, k++)
	{
		activitiesPtr[i] = num[k];                                //对这一段进行排序赋值
	}

}

 

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值