问题描述
假设有一个需要使用某一资源的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!)。