活动安排问题

196 阅读2分钟

问题表述:设有n个活动的集合E = {1,2,…,n},其中每个活动都要求使用同一资源,如演讲会场等,而在同一时间内只有一个活动能使用这一资源。每个活i都有一个要求使用该资源的起始时间si和一个结束时间fi,且si < fi 。如果选择了活动i,则它在半开时间区间[si, fi)内占用资源。若区间[si, fi)与区间[sj, fj)不相交,则称活动i与活动j是相容的。也就是说,当si >= fj或sj >= fi时,活动i与活动j相容。

由于输入的活动以其完成时间的非减序排列,所以算法greedySelector每次总是选择具有最早完成时间的相容活动加入集合A中。直观上,按这种方法选择相容活动为未安排活动留下尽可能多的时间。也就是说,该算法的贪心选择的意义是使剩余的可安排时间段极大化,以便安排尽可能多的相容活动。

算法greedySelector的效率极高。当输入的活动已按结束时间的非减序排列,算法只需O(n)的时间安排n个活动,使最多的活动能相容地使用公共资源。如果所给出的活动未按非减序排列,可以用O(nlogn)的时间重排。

例:设待安排的11个活动的开始时间和结束时间按结束时间的非减序排列如下:

算法greedySelector 的计算过程如下图所示。图中每行相应于算法的一次迭代。阴影长条表示的活动是已选入集合A的活动,而空白长条表示的活动是当前正在检查相容性的活动。

若被检查的活动i的开始时间Si小于最近选择的活动j的结束时间fi,则不选择活动i,否则选择活动i加入集合A中。 

贪心算法并不总能求得问题的整体最优解。但对于活动安排问题,贪心算法greedySelector却总能求得的整体最优解,即它最终所确定的相容活动集合A的规模最大。这个结论可以用数学归纳法证明。

活动安排问题实现:

 

复制 /* 主题:活动安排问题

  • 作者:chinazhangjie
  • 邮箱:chinajiezhang@gmail.com
  • 开发语言:C++
  • 开发环境:Vicrosoft Visual Studio
  • 时间: 2010.11.21 */

#include #include #include using namespace std ;

struct ActivityTime { public: ActivityTime (int nStart, int nEnd) : m_nStart (nStart), m_nEnd (nEnd) { } ActivityTime () : m_nStart (0), m_nEnd (0) { } friend bool operator < (const ActivityTime& lth, const ActivityTime& rth) { return lth.m_nEnd < lth.m_nEnd ; } public: int m_nStart ; int m_nEnd ; } ;

class ActivityArrange { public: ActivityArrange (const vector& vTimeList) { m_vTimeList = vTimeList ; m_nCount = vTimeList.size () ; m_bvSelectFlag.resize (m_nCount, false) ; } // 活动安排 void greedySelector () { __sortTime () ; // 第一个活动一定入内 m_bvSelectFlag[0] = true ;
int j = 0 ; for (int i = 1; i < m_nCount ; ++ i) { if (m_vTimeList[i].m_nStart > m_vTimeList[j].m_nEnd) { m_bvSelectFlag[i] = true ; j = i ; } }

    copy (m_bvSelectFlag.begin(), m_bvSelectFlag.end() ,ostream_iterator<bool> (cout, " "));
    cout << endl ;
}

private: // 按照活动结束时间非递减排序 void __sortTime () { sort (m_vTimeList.begin(), m_vTimeList.end()) ; for (vector::iterator ite = m_vTimeList.begin() ; ite != m_vTimeList.end() ; ++ ite) { cout << ite->m_nStart << ", "<< ite ->m_nEnd << endl ; } }

private: vector m_vTimeList ; // 活动时间安排列表 vector m_bvSelectFlag ;// 是否安排活动标志 int m_nCount ; // 总活动个数 } ;

int main() { vector vActiTimeList ; vActiTimeList.push_back (ActivityTime(1, 4)) ; vActiTimeList.push_back (ActivityTime(3, 5)) ; vActiTimeList.push_back (ActivityTime(0, 6)) ; vActiTimeList.push_back (ActivityTime(5, 7)) ; vActiTimeList.push_back (ActivityTime(3, 8)) ; vActiTimeList.push_back (ActivityTime(5, 9)) ; vActiTimeList.push_back (ActivityTime(6, 10)) ; vActiTimeList.push_back (ActivityTime(8, 11)) ; vActiTimeList.push_back (ActivityTime(8, 12)) ; vActiTimeList.push_back (ActivityTime(2, 13)) ; vActiTimeList.push_back (ActivityTime(12, 14)) ;

ActivityArrange aa (vActiTimeList) ;
aa.greedySelector () ;
return 0 ;

}