贪心算法

除了最优子结构性质之外,与动态规划不同的是,使用贪心算法解决的问题必须符合贪心选择性质

通过作出局部最优(贪心)选择来构造全局最优解。

在解决符合贪心选择性质的问题时,与动态规划算方法相比,贪心算法更简单、更高效。

活动安排问题

假定有一个n个活动的集合S={a1,a2,...,an},这些活动使用同一个资源(例如一个教室),而这个资源在某个时刻只能供一个活动使用。

每个活动ai都有一个开始时间si和一个结束时间fi。我们希望选出一个最大兼容活动集(其中两两活动都不重叠)。例如,考虑下面的活动集合S:

已按结束时间的单调递增顺序排序:

我们可以使用贪心算法解决这个问题(可以有其他的贪心选择方案):

每次我们从可以选择的活动集中选择最早结束的活动,并把它加入最优解。可以选择的活动集是S中开始时间大于fi(i是上次选择的活动)的活动。

因为活动已按结束时间的单调递增顺序排序,因此第一次选择a1加入最优解。然后每次执行贪心选择,得到最优解。

可以简单的证明一下:在满足相容条件下,使结束时间靠前的活动得到资源,这样为后续留下更多的时间,以使更多的活动得到安排。

伪代码

GREEDY-ACTIVITY-SELECTOR(s,f)
n=s.length
A={a1}
k=1
for m=2 to n
    if s[m]≥f[k]
        A=A∪{am}
        k=m
return A

其中A代表最大兼容的活动集,k记录了最近加入集合A的活动的下标。

因为活动已按结束时间的单调递增顺序排序,所以只需要每次找出可以选择的活动集中的第一个活动加入A中。

代码的实现与测试

 1 #define N 11
 2 #include <iostream>
 3 
 4 using namespace std;
 5 
 6 void greedy_activity_selector(int s[],int f[],int a[])
 7 {
 8     int i=0;
 9     a[i]=1;
10     int k=1;
11     for(int m=2;m<=N;++m)
12     {
13         if(s[m]>=f[k])
14         {
15             a[++i]=m;
16             k=m;
17         }
18     }
19 }
20 
21 
22 int main()
23 {
24     int s[]={0,1,3,0,5,3,5,6,8,8,2,12};
25     int f[]={0,4,5,6,7,9,9,10,11,12,14,16};
26     int a[N]={0};
27     greedy_activity_selector(s,f,a);
28     int i=0;
29     //输出最大兼容活动集的活动 
30     while(a[i])
31         cout<<a[i++]<<" ";
32     cout<<endl;
33     return 0;
34 }
View Code
原文地址:https://www.cnblogs.com/runnyu/p/4685885.html