4.1 活动选择问题
1.问题的理解与描述
假定有n个需要使用同一个这样的资源的活动,每次只能有一个活动使用该资源。每一个活动有一个开始时间 si,一个完成时间 fi,其中0 ≤ si < fi < ∞。如果区间[si , fi)和[sj , fj)不相交,活动ai和aj是相容的(即如果si≥ fj 或 sj ≤ fi,ai和aj相容)。活动选择问题是选取一个由相容活动构成的最大集合。
输入:按完成时间排好序的活动开始时间数组s,完成时间数组 f。
输出:表示一个最大的相容活动组的向量{x1, x2, …, xn},其中
xi={01第i个活动在此最大相容活动组中否则,i1,2,...,n。
2.最优子结构
定义集合
Sij=ak∈S:fi≤sk
定理4-1
考虑任一非空子问题Sij,并设am为Sij中最早完成的一个活动:
fm=minfk:ak∈Sij 。
则
(1)活动 am 包含在 Sij 的一个最大相容活动子集合中。
(2)子问题 Sim 是空的,所以选择 am 将使得 Smj 成为仅有的非空子问题。
4.算法的伪代码描述
- RECURSIVE-ACTIVITY-SELECTOR (s, f, i, j)
- 1 m ← i + 1
- 2 while m < j 且 sm < fi 求Sij中的第一个活动
- 3 do xm←0
- 4 m ← m + 1
- 5 if m < j
- 6 then xm←1
- 7 RECURSIVE-ACTIVITY-SELECTOR (s, f, m, j)
算法运行时间:Θ(n)
5 C++代码实现
- #ifndef _GREEDYACTIVITYSELECT_H
- #define _GREEDYACTIVITYSELECT_H
-
- int* RecusiveActivitySelector(int* s, int* f,int i,int j);
- #endif
- #include "GreedyActivitySelect.h"
-
- int* RecusiveActivitySelector(int* s, int* f,int i,int j)
- {
-
- static int * x=new int[j];
- int m=i+1;
- while(m<j&&s[m]<f[i])//求s[ij]中的第一个活动
- {
- x[m]=0;
- m++;
- }
- if(m<j)
- {
- x[m]=1;
- RecusiveActivitySelector(s,f,m,j);
- }
- return x;
-
- }
- #include "GreedyActivitySelect.h"
- #include <limits>
- #include <iostream>
- using namespace std;
-
- int main(int argc,char** argv)
- {
- int* x;
- int s[]={0,1,3,0,5,3,5,6,8,8,2,12,numeric_limits<int>::max()},
- f[]={0,4,5,6,7,8,9,10,11,12,13,14,numeric_limits<int>::max()};
- x=RecusiveActivitySelector(s,f,0,12);
- for(int i=1;i<12;i++)
- cout<<x[i]<<" ";
- cout<<endl;
- delete[]x;
- system("pause");
- return (EXIT_SUCCESS);
- }
运行结果:1 0 0 1 0 0 0 1 0 0 1