一、关于活动安排问题
1. 问题描述:
- 设有n个活动的集合E={i1,i2,…,in},其中每个活动都要求使用同一资源,如会场等,而在同一时间内只有一个活动能使用这一资源(争用!)。
- 每个活动i都有一个要求使用该资源的起始时间si和一个结束时间fi,且si<fi。
- 如果选择了活动i,则它在半开时间区间[si, fi)内占用资源。若区间[si, fi)与区间[sj, fj)不相交,则称活动i与活动j是相容的。也就是说,当si≥fj或sj≥fi时,活动i与活动j相容。
- 活动安排问题就是要在所给的活动集合中选出最大的相容活动子集合(活动数最多)。
2. 问题分析:
该算法的贪心选择的意义:
- 使剩余的可安排时间段极大化,已便安排尽可能多的相容活动
基本步骤:
- 用i代表第i个活动,s[i]代表第i个活动开始时间,f[i]代表第i个活动的结束时间,然后按结束时间从早到晚排序。
- 系统依次检查活动i是否与当前已选择的所有活动相容。若相容,活动i加入已选择活动的集合中,否则,不选择活动i,而继续检查下一活动与集合A中活动的相容性。且若活动i与之相容,则i成为最近加入集合A的活动,并取代活动j的位置。
- 挑选出结束时间尽量早的活动,并且满足后一个活动的起始时间晚于前一个活动的结束时间,全部找出这些活动就是最大的相容活动子集合。
举个例子:
- 设待安排的11个活动的开始时间和结束时间按结束时间从早到晚排列如下:
二、算法实现
1. 贪心算法
//活动安排问题 贪心算法
#include <iostream>
using namespace std;
void GreedySelector(int n, int s[], int f[], bool A[]);
int main()
{
const int n = 11; // 活动个数
bool A[n + 1]; // true为选择当前活动,false为不选择
int s[] = { 0,1,3,0,5,3,5,6,8,8,2,12 }; // 下标从1开始,活动开始时间
int f[] = { 0,4,5,6,7,8,9,10,11,12,13,14 }; // 下标从1开始,活动结束时间
cout << "各活动的开始时间,结束时间分别为:" << endl;
for (int i = 1;i <= n;i++)
cout << "[" << i << "]:" << "(" << s[i] << "," << f[i] << ")" << endl;
// 贪心算法-活动安排问题
GreedySelector(n, s, f, A);
// 输出
cout << "\n最大相容活动子集为:\n";
for (int i = 1;i <= n;i++)
if (A[i])
cout << "[" << i << "]:" << "(" << s[i] << "," << f[i] << ")" << endl;
return 0;
}
void GreedySelector(int n, int s[], int f[], bool A[])
{
A[1] = true; // 排序后第一个活动即是最早结束活动
int j = 1; // 记录最近一次加入A中的活动
// 依次检查活动i是否与当前已选择的活动相容
for (int i = 2;i <= n;i++)
{
if (s[i] >= f[j])
{
A[i] = true;
j = i;
}
else
A[i] = false;
}
}
2. 运行结果展示
·
三、友情链接~
- 其它一些常见算法请参阅此链接~
最后,非常欢迎大家来讨论指正哦!