问题描述:
这是一个调度竞争共享资源的多个活动的问题,目标就是选出一个最大的互相兼容的活动集合。假定有一个n个活动的集合S={a1,a2,...,an},这些活动使用同一个资源,而这个资源在某一时刻只能供一个活动使用。每个活动ai都是有一个开始时间si和一个结束时间fi,其中0 <= si < fi < 正无穷.如果被选中,任务ai发生在半开时间区间[si,fi)期间。如果两个活动ai和aj满足[si,fi)和[sj,fj}不重叠,则称它们是兼容的。也就是说,若si>=fj或sj>=fi,则ai和aj是兼容的。在活动选择问题中,我们希望选出一个最大兼容活动集。假定活动已按结束时间的单调递增顺序排序:
f1 <= f2 <= f3 <= ...<=fn-1<=fn
考虑下面的活动集合S:
对于活动选择问题,什么是贪心选择?直观上,我们应该选择这样一个活动,选出它后剩下的资源应能被尽量多的其他任务所用。现在考虑可选的活动,其中必然有一个最先结束。因此直觉告诉我们,应该选择S中最早结束的活动,因为它剩下的资源可供它之后尽量多的活动使用。(如果S中最早结束的活动有多个,我们可以选择其中任意一个)。换句话说,由于活动已按结束时间单调递增的顺序排序,贪心选择就是活动a1。
当做出贪心选择后,只剩下一个子问题需要我们求解:寻找在a1结束后开始的活动。为什么不需要考虑在a1开始前结束的活动呢?因为s1<f1是最早结束的活动,所以不会有活动的结束时间早于s1。因此,所有与a1兼容的活动都必须在a1结束之后开始。
下面附上递归贪心算法和迭代贪心算法的代码:
#include <iostream> #include <vector> using namespace std; #define N 11 void RECURSICE_ACTIVITY_SELECTOR(int s[], int f[], int k, int n, vector<int> &index) { //递归贪心算法 int m = k + 1; while(m <= n && s[m] < f[k]) m = m + 1; if (m <= n) { index.push_back(m); RECURSICE_ACTIVITY_SELECTOR(s, f, m, n, index); } else return ; } void GREEDY_ACTIVITY_SELECTOR(int s[], int f[], int n, vector<int> &index) { //迭代贪心算法 index.push_back(1); int k = 1; for (int m = 2; m <= n; m++) { if (s[m] > f[k]) { index.push_back(m); k = m; } } } int main() { int s[N+1], f[N+1]; s[0] = 0, f[0] = 0; s[1] = 1, f[1] = 4; s[2] = 3, f[2] = 5; s[3] = 0, f[3] = 6; s[4] = 5, f[4] = 7; s[5] = 3, f[5] = 9; s[6] = 5, f[6] = 9; s[7] = 6, f[7] = 10; s[8] = 8, f[8] = 11; s[9] = 8, f[9] = 12; s[10] = 2, f[10] = 14; s[11] = 12, f[11] = 16; vector<int> index; // RECURSICE_ACTIVITY_SELECTOR(s, f, 0, N, index); GREEDY_ACTIVITY_SELECTOR(s, f, N, index); for (vector<int>::iterator it = index.begin(); it != index.end(); it++) { cout<<*it<<" "; } cout<<endl; }
后来用动态规划做了一下,代码如下:
#include <iostream> #include <vector> using namespace std; #define N 11 int ACTIVITY_SELECTOR(int s[], int f[], int C[N+2][N+2], int recor[N+2][N+2]) { for (int i = 0 ; i < N+2; i++) { for (int j = 0; j < N+2; j++) { C[i][j] = 0; recor[i][j] = 0; } } /* for (int i = 0 ; i < N+2; i++) { for (int j = 0; j < N+2; j++) { cout<<C[i][j]<<" "; } cout<<endl; }*/ for (int L = 2; L <= N+2; L++) { int i = 0; int j = i+L; for ( ; i < N+2 && j < N+2; i++, j++) { if (s[j] >= f[i]) { for (int k = i+1; k < j; k++) { if (s[k] >= f[i] && f[k] <= s[j]) { int temp = C[i][k]+C[k][j]+1; C[i][j] = (temp > C[i][j])?temp:C[i][j]; recor[i][j] = k; } } } } } for (int i = 0 ; i < N+2; i++) { for (int j = 0; j < N+2; j++) { cout<<C[i][j]<<" "; } cout<<endl; } for (int i = 0 ; i < N+2; i++) { for (int j = 0; j < N+2; j++) { cout<<recor[i][j]<<" "; } cout<<endl; } return C[0][N+1]; } int maxSelect(int recor[N+2][N+2], int n, vector<int> & vec) { if (n == 0) { int sum = 0; for (vector<int>::iterator it = vec.begin(); it != vec.end(); it++) sum += *it; return sum; } int pivot = recor[0][n]; vec.push_back(pivot); maxSelect(recor, pivot, vec); } int main() { int s[N+1], f[N+1]; s[0] = 0, f[0] = 0; s[1] = 1, f[1] = 4; s[2] = 3, f[2] = 5; s[3] = 0, f[3] = 6; s[4] = 5, f[4] = 7; s[5] = 3, f[5] = 9; s[6] = 5, f[6] = 9; s[7] = 6, f[7] = 10; s[8] = 8, f[8] = 11; s[9] = 8, f[9] = 12; s[10] = 2, f[10] = 14; s[11] = 12, f[11] = 16; int C[N+2][N+2],recor[N+2][N+2]; vector<int> vec; cout<<ACTIVITY_SELECTOR(s,f,C,recor)<<endl; cout<<maxSelect(recor, N+1, vec); }