贪心算法—活动选择问题

4.1 活动选择问题
1.问题的理解与描述
假定有n个需要使用同一个这样的资源的活动,每次只能有一个活动使用该资源。每一个活动有一个开始时间 si,一个完成时间 fi,其中0 ≤ si < fi < ∞。如果区间[si , fi)和[sj , fj)不相交,活动ai和aj是相容的(即如果si≥ fj 或 sj ≤ fi,ai和aj相容)。活动选择问题是选取一个由相容活动构成的最大集合。
输入:按完成时间排好序的活动开始时间数组s,完成时间数组 f。
输出:表示一个最大的相容活动组的向量{x1, x2, …, xn},其中

xi={01第i个活动在此最大相容活动组中否则,i1,2,...,n。


2.最优子结构
定义集合
Sij=ak∈S:fi≤sk<fk≤sj ,为表示整个问题,添加两个假想的活动a0和an+1并约定f0 = 0及sn+1 = ∞。于是S = S0 n+1,而i和j的取值范围为0 ≤ i,j ≤ n + 1。显然只要i≥ j,就有Sij =∅。假定Sij的一个解包含活动ak,每一个都构成Sij中的活动的子集。设Aij是Sij的一个最优解, ak∈Aij 。利用 ak 产生两个子问题: Sik和Skj ,则Aij中Sik的解Aik和Skj的解Akj必对于: Sik和Skj也是最优的。
3.贪婪选择性
定理4-1
考虑任一非空子问题Sij,并设am为Sij中最早完成的一个活动:
fm=minfk:ak∈Sij 。

(1)活动 am 包含在 Sij 的一个最大相容活动子集合中。
(2)子问题 Sim 是空的,所以选择 am 将使得 Smj 成为仅有的非空子问题。
4.算法的伪代码描述

RECURSIVE-ACTIVITY-SELECTOR (s, f, i, j)
1 m ← i + 1
2 while m < j 且 sm < fi 求Sij中的第一个活动 
3   do xm←0
4     m ← m + 1
5 if m < j
6   then xm←1
7       RECURSIVE-ACTIVITY-SELECTOR (s, f, m, j)

算法运行时间:Θ(n)

5 C++代码实现

#ifndef _GREEDYACTIVITYSELECT_H
#define _GREEDYACTIVITYSELECT_H

int* RecusiveActivitySelector(int* s, int* f,int i,int j);
#endif
#include "GreedyActivitySelect.h"

int* RecusiveActivitySelector(int* s, int* f,int i,int j)
{

    static int * x=new int[j];
    int m=i+1;
    while(m<j&&s[m]<f[i])//求s[ij]中的第一个活动
        {
            x[m]=0;
            m++;
        }
    if(m<j)
        {
            x[m]=1;
            RecusiveActivitySelector(s,f,m,j);
        }
    return x;

}
#include "GreedyActivitySelect.h"
#include <limits>
#include <iostream>
using namespace std;

int main(int argc,char** argv)
{
  int* x;
  int s[]={0,1,3,0,5,3,5,6,8,8,2,12,numeric_limits<int>::max()},
      f[]={0,4,5,6,7,8,9,10,11,12,13,14,numeric_limits<int>::max()};
  x=RecusiveActivitySelector(s,f,0,12);
  for(int i=1;i<12;i++)
      cout<<x[i]<<" ";
  cout<<endl;
  delete[]x;
  system("pause");
  return (EXIT_SUCCESS);
}

运行结果:1 0 0 1 0 0 0 1 0 0 1

猜你喜欢

转载自blog.csdn.net/m0_62089210/article/details/128042275