活动选择问题:
Given a set S of n activities with and start time, Si and fi, finish time of an ith activity. Find the maximum size set of mutually compatible activities.
兼容活动概念:
Activities i and j are compatible if the half-open internal [si, fi) and [sj, fj) do not overlap, that is, i and j are compatible ifsi ≥ fj and sj ≥ fi
算法导论上提供了两种方法,一种是DP方法, 另一种是贪心算法,同时网上还提供了另一种DP的方法。下面对三种方法进行讲解:
1,算法导论上的DP方法:
先对每个活动ai按照活动结束时间fi从小到大排序,之后按照递归方程进行动态规划
-
-
-
-
-
-
-
-
-
-
-
-
- #include <iostream>
- #define MAX 105
- using namespace std;
- struct interval
- {
- int s;
- int f;
- int p;
- }inter[MAX];
- int cmp(const void* a, const void* b)
- {
- return ((interval*)a)->f - ((interval*)b)->f;
- }
- int N;
- int dp[MAX][MAX];
- int tracert[MAX][MAX];
- int output[MAX];
- void ACTIVITY_SELECTION_DYNAMIC()
- {
- int i, j, k, l;
- for(i = 0; i<= N+1; i++)
- dp[i][i] = 1;
- dp[0][0] = dp[N+1][N+1] = 0;
- for(l = 1; l<= N+1; l++)
- {
- for(i = 0; i<=N+1-l; i++)
- {
- j = i+l;
- dp[i][j] = 0;
- tracert[i][j] = -1;
- for(k = i+1; k < j; k++)
- {
- if(inter[k].s >= inter[i].f && inter[k].f <= inter[j].s)
- {
- if(dp[i][k] + dp[k][j] + 1 > dp[i][j])
- { dp[i][j] = dp[i][k] + dp[k][j] + 1;
- tracert[i][j] = k;
- }
- }
- }
-
- }
- }
- }
- void printout(int s, int f)
- {
- if(tracert[s][f] == -1) return;
-
- cout << tracert[s][f] << ' ';
-
- printout(s, tracert[s][f]);
- printout(tracert[s][f], f);
- }
- int main()
- {
- cin >> N;
- int i, j, k;
- inter[0].s = inter[0].f = 0;
- inter[0].p = 1;
- for(i = 1; i<= N; i++)
- cin >> inter[i].s;
- for(i = 1; i<= N; i++)
- { cin >> inter[i].f;
- inter[i].p = 1;
- }
- inter[N+1].s = inter[N+1].f = (2<<29)-1;
- inter[N+1].p = 1;
-
- qsort(inter, N+2, sizeof(interval), cmp);
-
- ACTIVITY_SELECTION_DYNAMIC();
- cout << dp[0][N+1] << endl;
- printout(0, N+1);
- cout << endl;
-
- return 0;
- }
2. 算法导论上的贪心算法:
先对每个活动ai按照活动结束时间fi从小到大排序,每次选择最早结束的活动,
而这个活动的选择需要与前面所选的活动相容。
原始问题是S= S[0,n+1],设活动am1是S[0,n+1]中具有最早结束时间的活动,
下一个问题是S[m1, n+1],设选择活动am2为S[m1,n+1]中最早结束时间的活动,
则下一个子问题是S[m2,n+1],如此继续:
- #include <iostream>
- #define MAX 105
- using namespace std;
- struct interval
- {
- int s;
- int f;
- int p;
- }inter[MAX];
- int cmp(const void* a, const void* b)
- {
- return ((interval*)a)->f - ((interval*)b)->f;
- }
- int N;
- int tracert[MAX];
- int ACTIVITY_SELECTION_GREEDY()
- {
- memset(tracert, 0, N);
- tracert[0] = 1;
- int i, m;
- m = 1;
- int count= 1;
- for(int i = 1; i< N; i++)
- {
- if(inter[i].s >= inter[m].f)
- {
- tracert[i] = 1;
- m = i;
- count ++;
- }
- }
- return count;
- }
- void printout()
- {
- int i, j;
- for(i = 0; i< N; i++)
- if(tracert[i] == 1)
- cout << i+1 << ' ';
- cout << endl;
- }
- int main()
- {
- cin >> N;
- int i, j, k;
- for(i = 0; i< N; i++)
- cin >> inter[i].s;
- for(i = 0; i< N; i++)
- { cin >> inter[i].f;
- inter[i].p = 1;
- }
-
- qsort(inter, N, sizeof(interval), cmp);
-
- cout << ACTIVITY_SELECTION_GREEDY() << endl;
-
- printout();
-
- return 0;
- }
3. 网上提供的DP方法:
Before starting the dynamic programming algorithm itself, we do some precomputation, as follows. We first sort the activities according to fi nish time, so that f1 <=f2 <=.. <= fn. We also compute, for every activity i, a number H(i) defi ned as H(i) = max{l<=i-1&& l>=0 && fl<=si} .the maximum value of the empty set is 0. We can compute each value H(i) in time O(log n) using binary search, so all of the precomputation can be done in time O(n log n).
We now perform the four steps of the dynamic programming method.
Step 1:
Describe an array of values we want to compute.
For every integer i, 0 <=i<=n, de fine A(i) = the largest pro fit we can get by (feasibly) scheduling activities from {1; 2,.., i}.
The value we are ultimately interested in is A(n).
Step 2:
Give a recurrence.
A(0) = 0.
This is true because if we are not allowed to schedule any activities at all, then the highest pro fit we can make is 0.
Let 1 <=i <=n. Then A(i) = max{A(i-1); gi + A(H(i))}:
-
-
-
-
-
-
-
- #include <iostream>
- #define MAX 105
- using namespace std;
- struct interval
- {
- int s;
- int f;
- int p;
- }inter[MAX];
- int cmp(const void* a, const void* b)
- {
- return ((interval*)a)->f - ((interval*)b)->f;
- }
- int N;
- int A[MAX];
- int tracert[MAX];
- void ACTIVITY_SELECTION_DYNAMIC1()
- {
- memset(A, 0, N);
- memset(tracert, 0, N);
- int i, j, k;
- for(i = 1; i< N; i++)
- {
- for(j = i-1; j >= 0; j--)
- if(inter[j].f <= inter[i].s) break;
- A[i] = max(A[i-1], 1+A[j]);
- }
- }
- void printout()
- {
- int i = N-1, j;
- while(i >= 0)
- {
- if(A[i] == A[i-1])
- {
- tracert[i] = 0;
- i--;
- }
- else
- {
- tracert[i] = 1;
- for(j = i-1; j>= 0; j--)
- if(inter[j].f <= inter[i].s) break;
- i = j;
- }
- }
- for(i = 0; i< N; i++)
- if(tracert[i] == 1)
- cout << i+ 1 << ' ';
- cout << endl;
- }
- int main()
- {
- cin >> N;
- int i, j, k;
- for(i = 0; i< N; i++)
- cin >> inter[i].s;
- for(i = 0; i< N; i++)
- { cin >> inter[i].f;
- inter[i].p = 1;
- }
-
- qsort(inter, N, sizeof(interval), cmp);
-
- ACTIVITY_SELECTION_DYNAMIC1();
- cout << A[N-1] << endl;
- printout();
-
- return 0;
- }