贪心算法---活动选择问题

活动选择问题:就是给定一组活动的开始时间和结束时间,然后他们都需要使用到一个资源,这个资源每次只有一个活动可以用,要求求出一个最大的相互兼容的活动子集。

首先定义了一个集合Sij = {ak S :fi  sk <</span> fk  sj} , 其中S就是所有活动的集合,fi是活动ai的完成时间si是活动ai的开始时间。

这道题如果是用DP来解的话,就需要找到最优解的递归方程(其中c[i,j]是集合Sij中的最大兼容活动的个数):

《贪心算法---活动选择问题》

然后根据DP自底向上的解答方法进行求解,过程和矩阵连乘的差不多。

然而,根据下面的定理,我们可以用贪心的策略来解答这道题目:

《贪心算法---活动选择问题》

这样子就将DP的两个子问题变成了只有一个子问题,而且由于将结束时间已升序排序,所以要求出fm也是很简单的。

接下来的工资就变得很简单了,看下面的伪代码和图片即可

 

  1. RECURSIVE-ACTIVITY-SELECTOR(s, f, i, j)  
  2. 1 m ← i + 1  
  3. while m  < j and sm < fi ▹ Find the first activity in Sij.  
  4. 3     do m ← m + 1  
  5. if m < j  
  6. 5    then return {am} ∪ RECURSIVE-ACTIVITY-SELECTOR(s, f, m, j)  
  7. 6    else return Ø  

下面的图片是利用上面的递归算法求解的过程

 

《贪心算法---活动选择问题》

代码如下:

#include<iostream>
using namespace std;


/*
*start 活动开始时间;finish 活动结束时间(已排序);record 记录贪心算法中所记录的活动顺序
*返回最多活动数
*/

int Greedy_Activity_Selector(int *start,int *finish,int *record,int length)
{
	int actmin , i, j;
	record[0] = start[0];
	j = 0;
	actmin = finish[0];
	for(i = 1; i < length; i++)
	{
		if(start[i] > actmin)
		{
			actmin = finish[i];
			record[++j] = start[i];
		}

	}
	return (j + 1);
}

int main()
{
	int start[] = {1,3,0,5,3,5,6,8,8,2,12};
	int finish[] = {4,5,6,7,8,9,10,11,12,13,14};
	int record[11];

	int actnum = Greedy_Activity_Selector(start,finish,record,11);
	cout<<"The activity num is : "<<actnum<<endl;

	cout<<"it contains : ";
	for(int i = 0;i < actnum; i++)
		cout<<record[i]<<" ";
	cout<<endl;

	return 0;
}
    原文作者:贪心算法
    原文地址: https://blog.csdn.net/yujiaming493323/article/details/8752410
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞