greedy策略求解工作选择问题(一)

        工作选择问题是活动选择问题和背包问题的一个集成,因为背包问题的greedy思想是每次选择当前性价比最高的物品;同时活动选择问题的geedy思想不是选择价值最大的物品,而是根据具体的问题要求,即在所有活动结束前,一个人最多能完成多少个活动,所以活动选择问题的greedy思想是如果当前的活动能越早结束,则一个人将越能尽快的完成下一个活动,这样最后就能完成最多的活动,其中活动的结束时间和开始时间都有规定。

        而工作选择问题则包含结束时间和profit,那么上面两个问题就有2种可能的greedy策略,一是选择尽可能多的工作,二是根据profit从高到底进行选择;而2者都有一个要求就是每个工作都有一个结束时间,那么如果按照方法一来选择就是活动选择问题,但是不能保证得到的是最大的profit,因为最终的结果是profit最大化,所以greedy目标不符合,但是仍然能够得到一个不错的解;而方法二是根据当前profit最大进行选择,若profit最大的deadline为最后的结束时间,那么最大的profit就只有一个工作的profit累加,所以最终得到profit不能保证是最大的。那么到底该如何选择呢?肯定是存在一个最大的profit,那么到底应该如何去选择对应的greedy策略?既然是最终的目标是profit,那么按照greedy思想还是应该立足于profit,然后再选择当前结束时间最早的工作,即将profit和工作数结合起来考虑;而该方法并不能保证得到最优解,但是可以得到一个近似解。有待证明??

        回归到本文的工作选择问题,为了循序渐进的求解工作选择问题,本文对工作选择问题进行简化,即工作不设置开始时间,而且每个工作的时长都是1个小时,这样在不考虑时间的条件下,相当于单位时间内,profit越高则最后的profit越大,但是要注意的是每个工作都有一个结束时间,所以在选择profit的前提下,要满足下一个工作的deadline大于当前已做工作消耗时间的总和,因为是单位时间,所以程序实现中只要满足deadline>=count(worked)。

        程序实现的核心是将所有工作的profit按照从大到小进行排序,然后进行遍历选择条件(deadline>=count(worked))符合的即可,具体框架核心实现如下:

std::vector<Point> GreedyStrategy::jobSequencingProblem(vector<Point>num)
{
	mergeSortJob(num, 0, num.size() - 1);                    //先根据profit进行从大到小的排序

	vector<Point>result;
	if (num.size() > 0)
	{
		result.push_back(num[0]);
	}
	else
	{
		return result;
	}
	for (int j=1; j < num.size(); j++)
	{
		if (num[j].getX()>result.size())
		{
			result.push_back(num[j]);                    //保证每次都能优先放入当前最大的利润
		}
	}

	return result;
}

        注:本文对数据的存储通过将数据封装成对象进行存储,所以返回的是一个Point对象,该对象包括Job的Id,deadline,profit属性。所以在排序过程中不需要针对指针排序,即以前博客文中的map迭代器排序;而是直接按照vector存储变量进行排序,因为一个map就可存储n个数据对,若采用n个map和一个vector也可行,但空间复杂度会增加,并且在排序阶段还是要赋值迭代器进行排序,所以采用一个map即可存储,但map存储有一个适用性:数据属性最多2个(键值对);若数据属性2个以上,目前最好的方法是将数据封装成对象(变量),如本文的job对象。所以根据不同情况对数据进行存储,选择合适的数据结构(或对象封装)存储,算法自成。

      下面是对job按照profit进行排序的算法如下:

void GreedyStrategy::mergeSortJob(vector<Point>&num,int low ,int high) 
{
	if (low < high)
	{
		int mid = (low + high) / 2;
		mergeSortJob(num, low, mid);
		mergeSortJob(num, mid + 1, high);                            //mid+1最多等于high,因为只有当low==high时mid==high,而low必须<high才能进入递归
		conquerJob(num, low, mid, high);
	}
}

void GreedyStrategy::conquerJob(vector<Point>&num, int low, int mid, int high)
{
    //Point.getX()==deadline
	//Point.getY()==profit

	int i = low;
	int j = mid + 1;
	vector<Point>numC;
	while (i<=mid&&j<=high)
	{
		if (num[i].getY() < num[j].getY())
		{
			numC.push_back(num[j]);
			j++;
		}
		else
		{
			numC.push_back(num[i]);
			i++;
		}
	}

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

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

	for (int i = low, k = 0; i <= high&&k<numC.size(); i++)
	{
		num[i] = numC[k];
		k++;
	}
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值