磁带特点:读取文件时需将目标文件之前的文件顺序读一遍
设磁带上存储着$n$个文件,长度分别为$L[1, \ldots, n]$,读取第$k$个文件的开销为$c(k) = \sum_{i=1}^k L[i]$
随机读取一个文件的期望开销为$\Ebb[c] = \frac{1}{n} \sum_{k=1}^n \sum_{i=1}^k L[i]$
设$\pi$是一个排列,$\pi(i)$表示磁带上第$i$个文件的实际文件编号,随机读取一个文件的期望开销为$\Ebb[c(\pi)] = \frac{1}{n} \sum_{k=1}^n \sum_{i=1}^k L[\pi(i)]$
问题:文件如何排列可使期望开销最低?
暴力穷举:$\Omega(n!)$
动态规划?
最优子结构性:设$\pi(1), \ldots, \pi(n)$是$\{ \text{文件}1,\ldots, \text{文件}n \}$的最优存储顺序,则$\pi(2), \ldots, \pi(n)$是$\{ \text{文件}1,\ldots, \text{文件}n \}\setminus \{\text{文件}\pi(1)\}$的最优存储顺序
确定$\pi(1)$会产生$n$个规模为$n-1$的子问题;对每个子问题,确定$\pi(2)$会产生$n-1$个规模为$n-2$的子问题;……;对每个子问题,确定$\pi(n-1)$会产生$2$个规模为$1$的子问题;这些子问题各不相同,总数为$n!$,因此动态规划与暴力穷举复杂度相当!
初始磁带为空,文件集合为$\{ \text{文件}1,\ldots, \text{文件}n \}$
贪心选择:将文件集合中长度最短的文件存入磁带
和动态规划不同,贪心法每轮贪心选择后只产生一个子问题:选文件集合中长度最短的文件
引理:对$\forall \pi$,若存在$i$使得$L[\pi(i)] \ge L[\pi(i+1)]$,记$a = \pi(i)$、$b = \pi(i+1)$,交换文件$a$、文件$b$后得到的新排列为$\pi'$,则$\Ebb[c(\pi')] \le \Ebb[c(\pi)]$。
证明:交换文件$a$、文件$b$后
总的开销减少$\Ebb[c(\pi)] - \Ebb[c(\pi')] = L[\pi(i)] - L[\pi(i+1)] \ge 0$
设$L[1, \ldots, n]$的增序排列为$\pi^{\text{ins}}$,最优排列$\pi^\star$与$\pi^{\text{ins}}$的第一处不同位置$\ge k$,即$\pi^\star[k] \ne \pi^{\text{ins}}[k] = \pi^\star[t]$
$\pi^{\text{ins}}[1]$ | $\cdots$ | $\pi^{\text{ins}}[k-1]$ | $\pi^{\text{ins}}[k]$ | $\cdots$ | |
---|---|---|---|---|---|
$=$ | $=$ | $=$ | $\ne$ | ||
$\pi^\star[1]$ | $\cdots$ | $\pi^\star[k-1]$ | $\pi^\star[k]$ | $\cdots$ | $\pi^\star[t] = \pi^{\text{ins}}[k]$ |
由$\pi^{\text{ins}}$的单调性,$L[\pi^\star[t]] \le L[\pi^\star[k], \ldots, L[\pi^\star[t-1]]$,不断交换$\pi^\star[t]$与其前一个元素直到到达位置$k$,得到新排列$\pi'$,由引理知每次交换期望读取开销不增,故$\pi'$也是最优排列,且与$\pi^{\text{ins}}$的第一处不同位置$\ge k+1$
由归纳法知存在最优排列与$\pi^{\text{ins}}$的第一处不同位置$\ge n$,因此$\pi^{\text{ins}}$就是最优排列
假设除长度外,还有频率$F[1, \ldots, n]$
随机读取一个文件的期望开销为
$$ \begin{align*} \quad \Ebb[c(\pi)] = \frac{1}{n} \sum_{k=1}^n \sum_{i=1}^k L[\pi(i)] F[\pi(k)] \end{align*} $$
引理:对$\forall \pi$,若存在$i$使$\frac{L[\pi(i)]}{F[\pi(i)]} \ge \frac{L[\pi(i+1)]}{F[\pi(i+1)]}$,记$a = \pi(i)$、$b = \pi(i+1)$,交换文件$a$、文件$b$后得到的新排列为$\pi'$,则$\Ebb[c(\pi')] \le \Ebb[c(\pi)]$。
证明:交换文件$a$、文件$b$后
$$ \begin{align*} \quad \Ebb[c(\pi)] - \Ebb[c(\pi')] & = F[\pi(i+1)] L[\pi(i)] - F[\pi(i)] L[\pi(i+1)] \\ & = F[\pi(i+1)] F[\pi(i)] \left( \frac{L[\pi(i)]}{F[\pi(i)]} - \frac{L[\pi(i+1)]}{F[\pi(i+1)]} \right) \ge 0 \end{align*} $$
贪心选择:将文件集合中长度/频率最小的文件存入磁带
贪心法:分步操作,每步取局部最优,最终得到全局最优解
贪心法只对部分最优化问题有效
经典算法
现有$n$个活动$\Scal = \{ a_1, a_2, \ldots, a_n \}$,活动$a_i$的时间段为$[s_i, f_i)$
这些活动会使用同一资源且不能共用,如会场等
如果两个活动的时间段不重叠,则称它们是兼容的
输入:$\Scal = \{ a_1 = [s_1, f_1), a_2 = [s_2, f_2), \ldots, a_n = [s_n, f_n) \}$
输出:从$\Scal$中选出最大兼容活动集合
假设活动已按结束时间单调递增排序$f_1 \le f_2 \le \cdots \le f_n$
有$n = 11$个活动
$i$ | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 |
---|---|---|---|---|---|---|---|---|---|---|---|
$s_i$ | 1 | 3 | 0 | 5 | 3 | 5 | 6 | 8 | 8 | 2 | 12 |
$f_i$ | 4 | 5 | 6 | 7 | 9 | 9 | 10 | 11 | 12 | 14 | 16 |
$\{ a_3, a_9, a_{11} \}$、$\{ a_1, a_4, a_8, a_{11} \}$、$\{ a_2, a_4, a_9, a_{11} \}$是兼容活动集合
后两者都是最大兼容活动集合,最大兼容活动集合不唯一
设$\Scal_{ij}$表示$a_i$结束后开始、$a_j$开始前结束的活动集合
$$ \begin{align*} \quad \Scal_{ij} & = \{ a_k = [s_k, f_k) \mid f_i \le s_k < f_k \le s_j \} \\[10px] a_1, & ~ \ldots, ~ a_i, ~ \underbrace{\overbrace{a_{i+1}, ~ \ldots, ~ a_{k-1}}^{\Scal_{ik}}, ~ a_k, ~ \overbrace{a_{k+1}, ~ \ldots, ~ a_{j-1}}^{\Scal_{kj}}}_{\Scal_{ij}}, ~ a_j, ~ \ldots, ~ a_n \end{align*} $$
最优子结构性:设$\Acal_{ij}$是$\Scal_{ij}$的最大兼容活动集合并包含$a_k$
若$\Acal_{ik}$不是最大,存在$\Acal'_{ik}$更大,则$\Acal'_{ik} \cup \{a_k\} \cup \Acal_{kj}$更大,矛盾
设$\Acal_{ij}$包含$a_k$,$\Acal_{ij} = \Acal_{ik} \cup \{a_k\} \cup \Acal_{kj}$
令$c[i,j] = |\Acal_{ij}|$表示$\Scal_{ij}$的最大兼容活动集合的大小
$$ \begin{align*} \quad c[i,j] & = c[i,k] + c[k,j] + 1 \\[6px] \Longrightarrow & ~ c[i,j] = \begin{cases} 0, & \Scal_{ij} = \emptyset \\ \max_{a_k \in \Scal_{ij}} \{ c[i,k] + c[k,j] + 1 \}, & \Scal_{ij} \ne \emptyset \end{cases} \end{align*} $$
动态规划:时间复杂度$\Theta(n^3)$,空间复杂度$\Theta(n^2)$
初始化最大兼容活动集合$\Acal = \emptyset$,不断将与$\Acal$兼容的活动加入$\Acal$
贪心选择:选择与$\Acal$兼容的活动中结束时间最早的
时间复杂度
贪心选择使剩余可安排时间最大化,给未来留下足够的余地
自顶向下递归实现,每次选择将问题转化成一个规模更小的问题
def activity_selector_rec(k, a): m = k + 1 while m < n and s[m] < f[k]: # 贪心选择寻找ak之后最早结束的活动 m = m + 1 if m < n: # 若找到 将其加入集合 递归寻找下一个兼容活动 a.append(m) # 将am加入集合 activity_selector_rec(m, a)
尾递归 => 迭代,一重 for 循环时间复杂度$\Theta(n)$
def activity_selector_greedy(): a = [1] # a1直接选择 k = 1 for m in range(1, n): # 从前向后遍历a1之后的活动 if s[m] > f[k]: # 若找到ak之后最早结束的活动am a.append(m) # 将am加入集合 k = m # 从am之后的活动中继续寻找 return a
设贪心法得到的兼容活动集合为
$$ \begin{align*} \quad S = \{ g_1, ~ g_2, ~ \ldots, g_{i-1}, ~ g_i, ~ g_{i+1}, ~ \ldots, ~ g_k \} \end{align*} $$
某个最大兼容活动集合为
$$ \begin{align*} \quad S^\star = \{ g_1, ~ g_2, ~ \ldots, g_{i-1}, ~ c_i, ~ c_{i+1}, ~ \ldots, ~ c_l \} \end{align*} $$
将$c_i$替换为$g_i$得到新的最大兼容活动集合
$$ \begin{align*} \quad S' = \{ g_1, ~ g_2, ~ \ldots, g_{i-1}, ~ g_i, ~ c_{i+1}, ~ \ldots, ~ c_l \} \end{align*} $$
由归纳法$\{ g_1, ~ g_2, ~ \ldots, g_{i-1}, ~ g_i, ~ \ldots, ~ g_k, ~ c_{k+1}, ~ \ldots, ~ c_l \}$是最大兼容活动集合,由贪心法的选择知$k = l$
最优子结构和可贪心选择是贪心法的两个关键
压缩一个只包含 a、b、c、d、e、f 的 10w 个字符的数据文件
字符 | a | b | c | d | e | f |
---|---|---|---|---|---|---|
频率 | 45 | 13 | 12 | 16 | 9 | 5 |
定长编码 | 000 | 001 | 010 | 011 | 100 | 101 |
变长编码 | 0 | 101 | 100 | 111 | 1101 | 1100 |
前缀码:码字互不为前缀,可以保证解码时无歧义
0101100 -> abc
左:定长编码树,右:变长编码树
最优编码树必然是满二叉树(右),每个内部结点有两个子结点
设$\Ccal$为字符表,对$\forall c \in \Ccal$,令$c.f$为$c$在文件中出现的频率
设$\Tcal$为任意前缀编码树,令$d_{\Tcal}(c)$表示字符$c$对应的叶子结点在$\Tcal$中的深度,也是$c$的码字的长度
采用编码方案$\Tcal$时,文件的编码长度
$$ \begin{align*} \quad B(\Tcal) = \sum_{c \in \Ccal} c.f \times d_{\Tcal}(c) \end{align*} $$
使得$B(\Tcal)$最小的前缀码称为最优前缀码
霍夫曼编码是一种最优前缀码
字符 | a | b | c | d | e | f |
---|---|---|---|---|---|---|
频率 | 45 | 13 | 12 | 16 | 9 | 5 |
最终霍夫曼编码树为
字符 | a | b | c | d | e | f |
---|---|---|---|---|---|---|
频率 | 45 | 13 | 12 | 16 | 9 | 5 |
编码长度$B(\Tcal) = \sum_{c \in C} c.f \times d_{\Tcal}(c)$
$B(\Tcal)$也等于编码树中所有结点频率值的和
证明依赖以下事实:
满二叉树:$|\text{内部结点}| = |\text{叶子结点}| - 1 = |\Ccal| - 1$
内部结点均是由其它两个结点合并出来的
贪心选择:每次选频率最低的两个结点合并
设$x$和$y$是$\Ccal$中频率最低的两个字符,则存在$\Ccal$的一个最优前缀码,在对应的编码树中,$x$和$y$是一对最深的兄弟叶子结点
证明:反设$\Tcal$是最优编码树,$x$和$y$不是一对兄弟叶子结点
将$x$和$y$与$\Tcal$中最深的一对兄弟叶子结点$a$和$b$交换会如何?
设$a$、$x$交换后的新树为$\Tcal'$,$d_{\Tcal'}(a) = d_{\Tcal}(x)$、$d_{\Tcal'}(x) = d_{\Tcal}(a)$
不难证明$\Tcal'$也是最优前缀树,同理再将$b$、$y$交换后依然还是
$$ \begin{align*} \quad \Delta B(\Tcal) & = a.f \times d_{\Tcal'}(a) + x.f \times d_{\Tcal'}(x) - a.f \times d_{\Tcal}(a) - x.f \times d_{\Tcal}(x) \\ & = a.f \times d_{\Tcal}(x) + x.f \times d_{\Tcal}(a) - a.f \times d_{\Tcal}(a) - x.f \times d_{\Tcal}(x) \\ & = \underbrace{(a.f - x.f)}_{\ge ~ 0} \underbrace{(d_{\Tcal}(x) - d_{\Tcal}(a))}_{\le ~ 0} \le 0 \end{align*} $$
$$ \begin{align*} \quad \qquad \quad \Tcal \qquad \qquad \qquad \qquad \quad \quad \Tcal' \end{align*} $$
设$\Ccal' = \Ccal \setminus \{ x,y \} \cup \{ z \}$,$z.f = x.f + y.f$,其它字符频率不变
设$\Tcal'$是$\Ccal'$的任一最优前缀码树,将$\Tcal'$中$z$对应的叶子结点替换为以$x$、$y$为孩子的内部结点,则得到的树$\Tcal$是$\Ccal$的一个最优前缀码树
$$ \begin{align*} \quad \qquad \qquad \qquad \qquad \Tcal' \qquad \qquad \qquad \qquad \quad ~ \Tcal \end{align*} $$
证明:反设$\Tcal$对应的前缀码不是$\Ccal$的最优前缀码
最优前缀码树为$\Tcal''$,于是$B(\Tcal'') < B(\Tcal)$
将$\Tcal''$中的$x$、$y$和它们的父节点整体替换成$z$,得到$\Tcal'''$
注意编码长度等于树中所有结点频率值的和
$B(\Tcal''') = B(\Tcal'') - x.f - y.f$、$B(\Tcal) = B(\Tcal') + x.f + y.f$
两式相加可得$B(\Tcal''') = B(\Tcal'') - B(\Tcal) + B(\Tcal') < B(\Tcal')$
故$\Tcal'$不可能是$\Ccal'$的最优前缀码树,矛盾!
前一个命题表明选择频率最低的两个字符可以构造最优前缀码树
后一个命题表明将频率最低的两个字符$x$、$y$合并成$z$后加入字符集合,由此构造出的最优前缀码树再将$z$对应的叶子结点作为内部结点分解成$x$、$y$两个叶子结点,依然还是最优前缀码树
输入:带权无向图$\Gcal = (\Vcal, \Ecal)$,其中$\Vcal$为边集、$\Ecal$为点集,边上的权重由函数$w: \Ecal \mapsto \Rbb$给出
输出:最小权重生成树$\Tcal$
初始化边集$\Acal = \emptyset$,之后每轮选择一条边$(u,v)$加入$\Acal$
在此过程中保证$\Acal$始终是某棵最小生成树的子集
问题:如何选择边$(u,v)$?
切割:无向图$\Gcal = (\Vcal, \Ecal)$的切割$(\Scal, \Vcal \setminus \Scal)$是$\Vcal$的一个划分
横跨切割边:边的两个端点分属于$\Scal$和$\Vcal \setminus \Scal$,例如$(a,h)$
尊重:如果集合$\Acal$中没有横跨切割的边,称该切割尊重$\Acal$
轻量边:横跨切割边中权重最小的边,例如$(c,d)$
贪心:每轮对任意尊重当前$\Acal$的切割,选择轻量边$(u,v)$加入
正确性证明:设$\Tcal$是任一包含$\Acal$的最小生成树,但$(u,v) \not \in \Tcal$
不妨设$\Tcal$中$u$到$v$的路径$p = \class{yellow}{u \rightsquigarrow w \rightsquigarrow x} \rightsquigarrow \class{blue}{b \rightsquigarrow a \rightsquigarrow v}$
$(u,v)$横跨切割,$p$中也必有一边横跨切割,不妨设为$(x,b)$
当前切割尊重$\Acal$,故$(x,b) \not \in \Acal$
记$\Tcal' = \Tcal \setminus \{ (x,b) \} \cup \{ (u,v) \}$
$w(u,v) \le w(x,b)$,$\Tcal'$也是最小生成树
$\Acal \cup \{ (u,v) \} \subseteq \Tcal'$
Kruskal 算法:$\Acal$始终是一个森林
Prim 算法:$\Acal$始终是一棵树
$\Acal$始终是一个森林,每次加入连接$\Acal$中两棵树的权重最小边
$\Acal$始终是一个树,每次加入连接$\Acal$和$\Acal$之外结点的权重最小边
算法导论 3rd
16.1-4、16.2-7、16.3-3、16-1
求以下背包问题的最优解:
$n=7$,$M=15$,$\pv = [10,5,15,7,6,18,3]$,$\wv = [2,3,5,7,1,4,1]$