回溯法求解活动安排问题

问题描述

假设有一个需要使用某一资源的n个活动所组成的集合S,S={1,…,n}。该资源任何时刻只能被一个活动所占用,活动i有一个开始时间bi和结束时间ei(bi<ei),其执行时间为ei-bi,假设最早活动执行时间为0。
一旦某个活动开始执行,中间不能被打断,直到其执行完毕。若活动i和活动j有bi≥ej或bj≥ei,则称这两个活动兼容。
设计算法求一种最优活动安排方案,使得所有安排的活动个数最多。

问题求解

采用回溯法求解,相当于找到S={1,…,n}的某个排列即调度方案,使得其中所有兼容活动个数最多,显然对应的解空间是一个是排列树。
直接采用排列树递归框架实现,对于每一种调度方案求出所有兼容活动个数,通过比较求出最多活动个数maxsum,对应的调度方案就是最优调度方案bestx,即为本问题的解。

对于一种调度方案,如何计算所有兼容活动的个数呢?因为其中可能存在不兼容的活动。
例如,下表的4个活动,若调度方案为(1,2,3,4),求所有兼容活动个数的过程如下:
在这里插入图片描述
置当前活动的结束时间laste=0,所有兼容活动个数sum=0。
活动1:其开始时间为1,大于等于laste,属于兼容活动,选取它,sum增加1,sum=1,置laste=其结束时间=3。
活动2:其开始时间为2,小于laste,属于非兼容活动,不选取它。
活动3:其开始时间为4,大于等于laste,属于兼容活动,选取它,sum增加1,sum=2,置laste=其结束时间=8。
活动4:其开始时间为6,小于laste,属于非兼容活动,不选取它。
该调度方案的所有兼容活动个数sum为2。

产生所有排列,每个排列x=(x[1],x[2],…,x[n])对应一种调度方案
计算每种调度方案的兼容活动个数sum
比较求出最大的兼容活动个数maxsum和最优方案bestx

代码

struct Action
{
	int b;//开始时间
	int e;//结束时间
};
int n = 4;
Action A[] = { {0,0},{1,3},{2,5},{4,8},{6,10} };

int x[MAXN];//临时解向量
int bestx[MAXN];//最优解向量
int laste = 0;//结束时间
int sum = 0;
int maxsum = 0;

void dfs(int i)
{
	if (i > n)
	{
		if (sum > maxsum)
		{
			maxsum = sum;
			for (int j = 1; j <= n; j++)
				bestx[j] = x[j];
		}
	}
	else
	{
		for (int j = i; j <= n; j++)
		{
			swap(x[i], x[j]);
			int sum1 = sum;
			int laste1 = laste;
			if (A[x[j]].b >= laste)//开始时间大于当前结束时间
			{
				sum++;
				laste = A[x[j]].e;
			}
			dfs(i + 1);
			//回溯
			swap(x[i], x[j]);
			sum = sum1;
			laste = laste1;
		}
	}
}

void dispasolution()
{
	int laste = 0;
	for (int j = 1; j <= n; j++)
	{
		if (A[bestx[j]].b >= laste)
		{
			cout << "选取活动" << bestx[j] << " ";
			laste = A[bestx[j]].e;//更改为当前活动的结束时间
		}
	}
}

算法分析

该算法对应解空间树是一棵排列树,与求全排列算法的时间复杂度相同,即为O(n!)。

  • 2
    点赞
  • 44
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
任务分配问题是一个经典的优化问题,通常使用回溯法进行求解。这里给出一种基本的回溯法求解任务分配问题的算法: 1. 定义状态表示:对于任务分配问题,我们可以使用一个长度为n的数组,其中第i个元素表示第i个任务被分配给了哪个人,初始状态为全0数组。 2. 定义状态扩展函数:状态扩展函数用于生成所有可能的下一步状态。对于任务分配问题,我们可以枚举当前未分配任务的人员,将当前未分配任务分配给该人员,生成新的状态。如果当前状态已经是一个合法解,则直接返回该解。 3. 定义剪枝函数:剪枝函数用于排除一些显然不可能达到最优解的状态,以减少搜索时间。对于任务分配问题,我们可以使用贪心策略,将当前未分配任务的人员按照某种规则排序,然后优先考虑分配给排名靠前的人员,如果发现当前状态已经不可能得到更好的解,则可以剪枝返回。 4. 实现回溯算法使用上述状态表示、状态扩展函数和剪枝函数,实现回溯算法。回溯算法的基本思路是深度优先搜索所有可能的状态,直到找到一个合法解或者搜索完所有状态。 5. 优化算法效率:可以通过一些技巧来优化算法效率,例如使用启发式搜索、剪枝等方法。 总的来说,回溯法是一种基本的求解任务分配问题的方法,但是对于大规模问题,会面临指数级别的搜索空间,因此需要结合其他技术进行优化。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值