一、算法要求
该问题要求高效地安排一系列争用某一公共资源的活动。贪心算法提供了一个简单、漂亮的方法,使尽可能多的活动能兼容地使用公共资源。
设有n个活动的集合E={1,2,…,n},其中每个活动都要求使用同一资源,如演讲会场等,而在同一时间内只有一个活动能使用这一资源。每个活动i都有要求使用该资源的起始时间s1和结束时间fi,且s<fi。如果选择了活动i,则它在半开时间区间[si,fi)内内占用资源。
若区间[si,f)与区间[sj,f)不相交,则称活动i与活动j是相容的。也就是说,当si≥f;或s;≥fi时,活动i与活动j相容。活动安排问题就是要在所给的活动集合中选出最大的相容活动子集合。
求解活动安排问题的贪心算法 GreedySelector中,各活动的起始时间和结束时间存储于数组s和f中,且按结束时间排列的非减序列:f1≤f2≤…≤fn。如果给出的活动未按此序排列,可以用O(nlogn)做时间重排。
1. 思路
- 在对问题求解时,总是做出在当前看来是最好的选择(贪心)。
- 不从整体最优上加以考虑,所做出的仅是在某种意义上的局部最优解。
- 贪心算法不是对所有问题都能得到整体最优解,但对范围相当广泛的许多问题,它能产生整体最优解或者是整体最优解的近似解。
2. 示例
二、完整代码
1. 主文件
main.cpp:
// Project1: 活动安排
#include<iostream>
#include<iomanip>
using namespace std;
const int N = 11;
template<class Type>
void GreedySelector(int n, Type s[], Type f[], bool x[]){
x[1] = true;
int j = 1;
for (int i = 2; i <= n; i++){//检查活动i
if (s[i] >= f[j]){
x[i] = true;
j = i;
}
else
x[i] = false;
}
}
int main(){
int s[] = { 0,1,3,0,5,3,5,6,8,8,2,12 }, //下标对齐,从1开始,活动开始数组
f[] = { 0,4,5,6,7,8,9,10,11,12,13,14 }; //活动结束数组
bool x[N + 1]; //判断数组
cout << "#The start and end times of the event are as follows: " << endl;
cout << setw(7) << left << "#No.:";
for (int i = 1; i <= N; i++) {
cout << setw(3) <<i;
}
cout << endl;
cout << setw(7) << left << "#Start:";
for (int i = 1; i <= N; i++) {
cout << setw(3) <<s[i] ;
}
cout << endl;
cout << setw(7) << left << "#End:";
for (int i = 1; i <= N; i++) {
cout << setw(3) << f[i];
}
cout << endl;
GreedySelector(N, s, f, x);
cout << "\n#The best event schedule is as follows: " << endl;
for (int i = 1; i <= N; i++){
if (x[i] == 1){
cout << setw(3) << right << i;
}
}
return 0;
}
2. 效果展示
输入:
输出:
三、补充
算法复杂度分析:
(1)时间复杂度:在该算法中,问题的规模就是会议总个数n。显然,执行次数随问题规模的增大而变化。首先在成员函数setMeet::init()中,输入n个结构体数据。输入作为基本语句,显然,共执行n次。而后在调用成员函数setMeet:solve()中进行排序,易知 sort排序函数的平均时间复杂度为O(nlogn)。随后进行选择会议,贡献最大的为if(meet[i].beg>=last)语句,时间复杂度为O(n),总时间复杂度为O(n +nlogn)= O(nlogn)。
(2)空间复杂度:在该算法中,meet[]结构体数组为输入数据,不计算在空间复杂度内。辅助空间有i、n、ans等变量,则该程序空间复杂度为常数阶,即O(1)。
文档供本人学习笔记使用,仅供参考。