贪心算法
目录
一、区间调度问题(贪心算法领先)
1. 区间调度问题
有标记为1,2,……,n的n个需求,每个需求 i 由开始时间s(i)和结束时间f(i)指定,如果没有两个需求在时间上重叠,我们就说需求的子集是相容的。我们的目标是接受一个最大的相容子集,也叫最优子集。
2.设计贪心算法
基本思想:是用一个简单的规则来选择第一个需求 ,一旦接受了需求 ,我们就拒绝与 不相容的需求,然后选择下一个被接受的需求 ,拒绝与 不相容的需求,按这种方式走完所有需求。
决定规则:
1.接受最早开始的需求,则可能拒绝一大批较短时间区间的需求,如图a。
2.接受最小时间区间的需求,则最短的区间可能阻止我们接受其他构成最优解的区间,如图b。
3.接受有着最少不相容个数的需求,即选择最少“冲突”的区间,虽然可以在图b的例子中获取最优解,但在图c的例子中,则仅接受了第二行中间的需求,拒绝了最优解,因此这个规则也不可取。
4.接受最早结束的需求。能够保证我们的资源尽可能早的被释放。
具体算法:
初始 令R是所有需求的集合,设A为空
While R 不空
选择一个有最早结束时间的需求i∈R
把i加到A中
从R中删除与需求i不相容的所有需求
Endwhile
返回集合A作为被接受的需求集合
3.分析算法
证明算法的正确性:
设 是算法返回的集合,是一个最优的区间集合。
证明思想:证明贪心算法“领先”于这个解O。
命题4.1 A是一个相容的需求集。
命题4.2 对所有的指标r≤k,我们有 。
定理4.3 贪心算法返回一个最优的集合A 。
算法的实现:
n = 0
start = []
end = []
R = [] #所有的集合
A = [] #被接受的集合
def getinterval():
n = int(input())
start = [int(n) for n in input().split()]
end = [int(n) for n in input().split()]
for i in range(n):
R.append([start[i],end[i]])
def interval():
n = len(R)
a = 0 #被接受的集合总数
t = 0 #时间
for i in range(n):
if t<R[i][0]:
a+=1
A.append([R[i][0],R[i][1]])
t = R[i][1]
print('最多工作%d项工作'%a)
print(A)
getinterval()
interval()
算法的运行时间:
4. 调度所有的区间问题(多区间调度)
目标:把所有的区间划分到多个资源。
命题4.4 在任何区间划分的实例中,资源数必须至少是区间集合的深度。
具体算法:
任意打破区间的并列,根据开始时间对他们排序
设 表示按这个次序排列的区间
For j =1,2,3,……,n
For 每个按照上述次序领先于 并且与它重叠的区间
从对Ij的考虑中排除 的标签
Endfor
If在{1,2,……,d}中存在任何还没有被排除的标签 then
分配一个没排除的标签给
Else
保留 不分配标签
Endif
Endfor
分析算法:
命题4.5 如果我们使用上述贪心算法,每个区间将被分配一个标签,且没有两个重叠的区间接受同样的标签。
命题4.6 上述贪心算法使用与区间集合深度等量的资源为每个区间安排一个资源,这是所需资源的最优数量。
算法的实现:
#R为所有区间,r为标签
def intervalall():
n = len(R)
t = 0 #time
s = 0 #endtime
num = 0 #资源数
for j in range(n):
if r[j]!=0:continue
else:
num+=1
r[j] = num
t = R[j][1]
for i in range(n):
print(t,R[i][0])
if (t<R[i][0])and(r[i]==0):
r[i] = num
t = R[i][1]
print(r)
print(num)
print(r)
二、最小延迟调度(一个交换论证)
1. 最小延迟调度问题
现有单一资源和一组使用资源的n个需求,每个需求需要一个时间区间,每一个需求i有一个截止时间 ,并且它要求一个长为 的连续的时间区间(即区间长度为 ),他想被安排在截止时间之前的任何时刻,每个被接受的需求必须被分配一个长为 的时间区间,且不同的需求被分在不重叠的区间。
2. 设计算法
最早截止时间优先,具有最早截止时间的任务完成得更早一些。
具体算法:
按照它们的截止时间的次序对任务排序
为使符号简单,假定
初始f=s