您的位置:首页 > 其它

基于贪心策略的活动选择问题

2017-03-16 01:09 369 查看
关于活动选择的问题:
1:问题描述
n个活动都有自己的开始和结束时间,但是每个活动都是占用同一个教室,问怎么安排活动能够使一天

内安排的活动总数最多。

2:算法解决思想
活动总共是从1到n总共n个,假设Sij表示的是活动ai结束之后,aj开始之前的全部活动,现在我们来求

Sij的一个最大兼容活动子集。假设Aij是满足这样条件的一个最大活动子集,并且它包含了活动ak。那么可

以将Aij分割为3部分,既Aij = Aik + ak + Akj。则Sij的最大兼容活动个数sum = |Aik| + 1 +|Akj|。
如果Aik不是活动Sik的一个最佳子集,那么必然存在一个Sik' > Sik,那么就会有sum' = |Aik’| + 1 + |Akj| > sum,

这根sum是Sij的最大兼容活动个数相违背,所以Aik必然是活动集Sik的一个最大兼容活动集,也就是说子问题Aik是子问题

的最优解。同理Akj也必然是子问题的最优解。这就满足了最优解的问题的子问题也是最优解的条件,预示着我们可以

使用动态规划来解决这个问题。

3:关键点的证明
虽然使用动态规划可以解决问题,但是动态规划的时间复杂度要高些,并且动态规划要解决的子问题比较多些。

贪心选择就是从直觉上选择当前应该是最佳的解决方案,那么两个子问题中因为有了贪心选择就只剩下一个待解决的

子问题了。在活动选择这里,我们做的选择就是结束最早的活动。那怎么证明最早结束的就一定存在在最优解中呢?
在这里有个定理:在非空子问题Sk中,如果am是Sk中结束最早的活动,那么am在Sk的某个最大兼容活动集中。
证明是这样的:设Ak是Sk的一个最大兼容活动集,且aj是Ak中最早结束的活动,若aj == am,则证明了定理,若

aj≠am,令Ak' = (Ak - aj)∪am,因为f(am) < f(aj),所以Ak’中的活动必然是不相交的,那么就可以得出Ak'也是Sk

的一个最大兼容活动子集。从而证明了定理。

4 代码实现

由于python代码接近于伪代码,所以这里采用python来实现算法

<1> 递归
# k is the activity which has finished and n has't finished
def greedyActivity(s, f, k, n):
m = k + 1
while (m <=n and s[m] < f[k]):
m += 1
if(m <= n):
x = [m];
x += greedyActivity(s, f, m, n)
return x
else:
return []

#in order let the first activity in the result ,we must make up
#an activity as the one  activity finished before the first
s = [-2,1,3,0,5,3,5,6,8,8,2,12]
f = [-1,4,5,6,7,8,9,9,10,11,12,14,16]
k = 0
n = 11
z = greedyActivity(s,f,k,n)
print(z)


<2> 非递归 
#make a for loop and every time findintg the earlist finished activity
# then change the k value
def greedyActivityAdvance(s,f,k,n):
x = [s[1]]
k = 1
for m in range(2,n+1) :
if( s[m] >= f[k]):
x.append(m)
k = m
return x
s = [-2,1,3,0,5,3,5,6,8,8,2,12]
f = [-1,4,5,6,7,8,9,9,10,11,12,14,16]
k = 0
n = 11
zz = greedyActivityAdvance(s,f,k,n)
print(zz)


5 参考文献

算法导论
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息