Skip to content
Ayas_Lan's Blog
Go back

贪心算法

Edit page

区间调度问题

600*600

所选择的贪心算法: 选择的基准——每一个任务的结束时间。 伪代码:

sort jobs by their finish time so that f1 <= f2 <= ... <= fn
set A = none
for j = 1 to n:
   if j compatible with A:
      A = A union j
end for
return A

时间复杂度分析:

最优性的证明:

区间划分问题

设区间的深度:depth = 在任意给定的时间内所包括的最大间隔数目。

贪心算法: ——根据lecture的开始时间进行排序。

伪代码如下:

sort intervals by starting time so that s1 <= s2 <= ... <= sn
set d = none
for j = 1 to n:
    if (lecture j compatible to some classroom k):
       schedule j to k
    else
        allocate a new classroom d + 1
        schedule j to d + 1
        d = d + 1
end for

如何判断是否有相容教室: 对于一个新区间,需要找到最早结束的教室——堆顶元素。 1,若当前区间开始时间 >= 堆顶元素结束时间 \rightarrow 复用该教室

每个区间最多触发两次堆的更新操作——2O(logD) = O(logD) <= O(logN)。故for循环整体的时间复杂度为O(NlogN)。 故整体算法的时间复杂度为O(NlogN).

最优性检验:

最小延迟调度问题

贪心算法: ——排序标准:最早结束的ddl优先。

伪代码:

sort n jobs by ddl
set t = 0
for j = 1 to n :
    assign j to interval [t, t + t_j]
    s_j = t, f_j = t+ t_j
    t = t + t_j
output interval [s_j, f_j]

最优性检验:

若贪心不是最优解: 则在最优解中一定存在相邻逆序对——di<djd_{i} < d_{j},但j安排在i前面。

贪心法最优性的证明策略

最优离线缓存策略——最远将来法

离线算法: 知道未来所有访问页面的序列。

603 策略: 当缓存满且发生miss项时,驱逐缓存中“未来最晚被再次访问的元素”

降低缺失率的策略:

只在请求某个数据项时才将其加载进缓存(不会在没有请求的时候,主动把 数据提前加载到缓存)

证明: 假设S在时间他将页面d加载如缓存,但此时没有对于d的请求。 当加载d时,S需要淘汰某个页面c。 存在两种情况:

SFFS_{FF}的最优性证明:(交换论证法)

硬币找零问题

目标:

贪心法的最优性证明: 先设定若干变量:P——1美分;N——5美分;D——10美分;Q——25美分。 可以得到,对于最优方案,存在如下的数量限制:

P<=4N<=1N+D<=2Q<=3\begin{aligned} P <= 4\\ N <= 1\\ N+D <= 2\\ Q <= 3 \end{aligned}

考虑在区间ck<=x<ck+1c_{k} <= x < c_{k+1}内进行找零,设贪心法会选择面值为ckc_{k}的硬币。 若任何最优解也必须选择面值为ckc_{k}的硬币。若不选择,其必须用若干个面值为c1,c2,...,ck1c_{1},c_{2},...,c_{k-1}的硬币来凑出x

选择断点问题

从A地到B地,中间有若干个加油站,加满油能开C的距离。 目标:在完成行程的前提下,加油次数越短越好。

贪心目标:在油箱耗尽之前,行驶得越远越好。

最优性证明:0=g0<g1...<gp=L0 = g_{0} <g_{1}...<g_{p} = L表示贪心策略选择的停靠点。 设0=f1<f2...<fq0 = f_{1} < f_{2} ... <f_{q}表示最优方法选择的停靠点。 设有f0=g0,f1=g1,...,fr=grf_{0} = g_{0},f_{1}=g_{1},...,f_{r}=g_{r}。那么在贪心策略的要求下,一定有gr+1>fr+1g_{r+1} > f_{r+1}. 先将fr+1f_{r+1}换为gr+1g_{r+1},则后续的加油次数也不会增加,则最大相同数目变为r+1。 以此类推,可以逐步将每一步都置换为贪心算法的停靠点。

聚类问题

目标: 给定一个整数k,找到一个k聚类,使得簇间间距最大。

single-link-k-聚类算法: 1,初始时,将每个店看做一个独立的簇。 2,在所有属于不同簇的点对中,找到距离最近的一对点,在之间连接一条边。 3,重复上述操作n-k次。

其就等价于使用Kruskal算法,按边权从小到大加入边,生成最小生成树后,再删除最后加入的k-1条最大权重边。

最优性证明: 定义: 设CC^{*}为删除MST最大k-1条边得到的聚类。 dd^{*}CC^{*}的最小间距(即被删除的第k-1大边的权值)

假设存在聚类C,其最小间距 > dd^{*}: 由于两者为不同的聚类,则必然存在点对(u, v),满足: 在cc^{*}中同簇,在c中异簇。 由于边(u, v)没有被删除,则说明其权值 < dd^{*}. 则说明C的最小间距 <=W(u,v)<=d<= W(u, v) <= d^{*}。 这就与假设相矛盾。


Edit page
Share this post on:

Previous Post
稳定匹配