|
| 1 | +\chapter{贪心算法} |
| 2 | + |
| 3 | +\begin{introduction} |
| 4 | + \item 区间调度问题 |
| 5 | + \item 任务调度问题 |
| 6 | + \item 另一个任务调度问题 |
| 7 | +\end{introduction} |
| 8 | + |
| 9 | + |
| 10 | +\section{概述} |
| 11 | +\begin{definition}{贪心算法} |
| 12 | + 在迭代的每一步根据某种规则取局部最优算法称为贪心算法。对同一个问题可能有许多贪心策略,每种策略有不同的规则,得到的结果也可能不同。 |
| 13 | + \\贪心算法主要使用交换法证明,即对任意假定的结果,逐步经过交换,每一步都使新的结果不差于原有的结果,最终得到经过选择的策略求出的解。由此证明经该策略得到的解是最优解。 |
| 14 | +\end{definition} |
| 15 | + |
| 16 | + |
| 17 | + |
| 18 | +\section{区间调度问题} |
| 19 | +\begin{example} |
| 20 | + 给定区间$I_1, I_2, \ldots, I_n$, |
| 21 | + $s_i$为$I_i$开始时间,$f_i$为$I_i$的结束时间($f_i>s_i$),$I_j=[s_j,f_j]$ |
| 22 | + \\目标:选出尽量多的区间,使两两互不重叠。 |
| 23 | +\end{example} |
| 24 | + |
| 25 | +\subsection{算法设计} |
| 26 | +\begin{figure}[hbt!] |
| 27 | + \centering |
| 28 | + \begin{subfigure}{.3\textwidth} |
| 29 | + \centering |
| 30 | + \begin{tikzpicture} |
| 31 | + \draw[|-|] (0, 0) -- node [above] {\scriptsize } (1, 0); |
| 32 | + \draw[|-|] (1.2,0) -- node [above] {\scriptsize } (2.2,0); |
| 33 | + \draw[|-|] (0.5 , -0.5) -- node [above] {\scriptsize } (1.5, -0.5); |
| 34 | + \end{tikzpicture} |
| 35 | + \caption{}\label{fig:counterexample1} |
| 36 | + \end{subfigure} |
| 37 | + \begin{subfigure}{.3\textwidth} |
| 38 | + \centering |
| 39 | + \begin{tikzpicture} |
| 40 | + \draw[|-|] (0, 0) -- node [above] {\scriptsize } (2.5, 0); |
| 41 | + \draw[|-|] (0.3, -0.5) -- node [above] {\scriptsize } (0.7, -0.5); |
| 42 | + \draw[|-|] (0.8, -0.5) -- node [above] {\scriptsize } (1.5, -0.5); |
| 43 | + \draw[|-|] (1.6, -0.5) -- node [above] {\scriptsize } (2.0, -0.5); |
| 44 | + \end{tikzpicture} |
| 45 | + \caption{}\label{fig:counterexample2} |
| 46 | + \end{subfigure} |
| 47 | + \begin{subfigure}{.3\textwidth} |
| 48 | + \centering |
| 49 | + \begin{tikzpicture} |
| 50 | + \draw[|-|] (0, 0) -- node [above] {\scriptsize } (1, 0); |
| 51 | + \draw[|-|] (1.2, 0) -- node [above] {\scriptsize } (2.2, 0); |
| 52 | + \draw[|-|] (2.4, 0) -- node [above] {\scriptsize } (3.4, 0); |
| 53 | + \draw[|-|] (3.6, 0) -- node [above] {\scriptsize } (4.4, 0); |
| 54 | + \draw[|-|] (0.6, -0.5) -- node [above] {\scriptsize } (1.6, -0.5); |
| 55 | + \draw[|-|] (0.6, -1) -- node [above] {\scriptsize } (1.6, -1); |
| 56 | + \draw[|-|] (0.6, -1.5) -- node [above] {\scriptsize } (1.6, -1.5); |
| 57 | + \draw[|-|] (1.8 , -0.5) -- node [above] {\scriptsize } (2.8, -0.5); |
| 58 | + \draw[|-|] (3.0 , -0.5) -- node [above] {\scriptsize } (4.0, -0.5); |
| 59 | + \draw[|-|] (3.0 , -1) -- node [above] {\scriptsize } (4.0, -1); |
| 60 | + \draw[|-|] (3.0 , -1.5) -- node [above] {\scriptsize } (4.0, -1.5); |
| 61 | + \end{tikzpicture} |
| 62 | + \caption{}\label{fig:counterexample3} |
| 63 | + \end{subfigure} |
| 64 | + \caption{贪心反例}\label{fig:counterexample} |
| 65 | +\end{figure} |
| 66 | + |
| 67 | +\paragraph*{反例} |
| 68 | +在本题中,我们可以选择的贪心策略有很多,以下三种均是贪心策略,但是并不能取得最优结果,说明如下。 |
| 69 | + |
| 70 | +\begin{enumerate} |
| 71 | + \item 以时间最短排序,反例如\autoref{fig:counterexample1} |
| 72 | + \item 以开始时间最早排序,反例如\autoref{fig:counterexample2} |
| 73 | + \item 选择冲突最少的区间,反例如\autoref{fig:counterexample3} |
| 74 | +\end{enumerate} |
| 75 | + |
| 76 | + |
| 77 | + |
| 78 | +\begin{figure}[hbt!] |
| 79 | + \centering |
| 80 | + \begin{tikzpicture} |
| 81 | + \draw[|-|] (0, 0) -- node [above] {\scriptsize 3} (3, 0); |
| 82 | + \draw[|-|] (5, 0) -- node [above] {\scriptsize 6} (6, 0); |
| 83 | + \draw[|-|] (0.3, -0.5) -- node [above] {\scriptsize 1 } (1.3, -0.5); |
| 84 | + \draw[|-|] (1.5, -0.5) -- node [above] {\scriptsize 2 } (2.5, -0.5); |
| 85 | + \draw[|-|] (3.1, -0.5) -- node [above] {\scriptsize 7 } (6.5, -0.5); |
| 86 | + \draw[|-|] (0.9, -1) -- node [above] {\scriptsize 4 } (3.6, -1); |
| 87 | + \draw[|-|] (3.8, -1) -- node [above] {\scriptsize 5 } (4.4, -1); |
| 88 | + \draw[|-|] (5.6 , -1) -- node [above] {\scriptsize 8 } (7, -1); |
| 89 | + \end{tikzpicture} |
| 90 | + \caption{任务区间}\label{fig:example22} |
| 91 | +\end{figure} |
| 92 | +\newpage |
| 93 | +因此,贪心策略的选取并不是随便的,而是需要依据对应的情况,例如\autoref{fig:example22},为了有更多的区间能被选中,从前往后看,每执行一个任务,我们需要使能够使用时间的开始时间尽量早,才能选取尽量好的下一个任务。该贪心策略说明如下。 |
| 94 | + |
| 95 | +令$Q=\{I_1, I_2, \ldots, I_n\},R=\varnothing$ |
| 96 | + |
| 97 | +\begin{enumerate} |
| 98 | + \item 对$Q$中$I_1, I_2, \ldots, I_n$以结束时间由小到大排序 |
| 99 | + \item 每次将Q中有最小结束时间且不与R中区间冲突的区间$I_i$加入R,将$I_i$从Q中移除,循环往复,直到无法加入为止 |
| 100 | +\end{enumerate} |
| 101 | + |
| 102 | +\subsection{算法分析} |
| 103 | +\paragraph*{正确性证明} |
| 104 | +\begin{itemize} |
| 105 | + \item 假定有一个更好的解$OPT'$,对其中的每一个区间进行排序,为$J_1‘,J_2',\ldots,J_n'$,而上面给出的贪心解为$J_1,J_2,\ldots,J_n$。 |
| 106 | + \item 从$i=1$开始置换将$OPT'$中的$J_i'置换为J_i$根据我们贪心策略的定义,易得$OPT'$中的区间依然不会冲突而且区间数维持不变。 |
| 107 | + \item 完成$OPT'$区间最后一个区间的置换后可知贪心解$OPT$的区间数$\geq OPT'$解的区间数 |
| 108 | +\end{itemize} |
| 109 | + |
| 110 | +\paragraph*{复杂度} |
| 111 | +该算法的时间复杂度即为排序所用时间的复杂度$O(nlogn)$,空间复杂度为$O(n)$。 |
| 112 | + |
| 113 | +\section{任务调度问题} |
| 114 | +\begin{example} |
| 115 | + 给定$n$个任务,对于第$i$个任务,给定完成该任务所需要的时间$t_i$和 |
| 116 | + 该任务的截止时间$d_i$,总体开始时间$S=0$,要求找出$\forall$任务$i$, |
| 117 | + 给定一个时间段$[s_i,f_i]$,其中$f_i - s_i = t_i$,且$s_i\geqslant s$ |
| 118 | + |
| 119 | + \begin{equation} |
| 120 | + s.t. \forall \space l_i = \begin{cases} |
| 121 | + f_i - d_i & f_i > d_i \\ |
| 122 | + 0 & f_i \leqslant d_i |
| 123 | + \end{cases} |
| 124 | + \end{equation} |
| 125 | + \\目标:令$L =\max(l_i)$,算法给出的L最小。 |
| 126 | +\end{example} |
| 127 | + |
| 128 | +\subsection{算法设计} |
| 129 | +\paragraph*{贪心策略选择} |
| 130 | +为了使最大子任务超时时间最短,一个比较自然的贪心思路是让截止时间早的任务优先执行。 |
| 131 | + |
| 132 | +\begin{remark} |
| 133 | + 假设对任意的任务截止时间$d_i \neq d_j$ |
| 134 | +\end{remark} |
| 135 | + |
| 136 | +\subsection{算法分析} |
| 137 | + |
| 138 | +\paragraph*{贪心策略正确性证明} |
| 139 | +\begin{enumerate} |
| 140 | + \item 假定存在一个其他策略产生的结果$OPT'$结果比我们的贪心策略结果$OPT$更好。 |
| 141 | + \item 那么$OPT'$中的任务序列必然有逆序,否则会与$OPT$结果相同,假设该逆序组合任务序号为$i$与$i+1$,其中$f_i>f_{i+1}$。 |
| 142 | + \item 我们现在把它调成顺序,即对他们的位置做交换,显然,这并不会影响他们前后的超时时间。假定他们的开始时间为$S$,消耗时间分别为$t_i$和$t_{i+1}$。对于$i$任务,之前的超时时间为$S+t_i-d_i$,之后的超时时间为$S+t_i+t_{i+1}-d_i$。对于$i+1$号任务,之前的超时时间为$S+t_i+t_{i+1}-d_{i+1}$,之后的超时时间为$S+t_{i+1}-d_{i+1}$。 |
| 143 | + \item 根据我们的假设$d_{i+1}<d_i$。易得$S+t_i+t_{i+1}-d_i<S+t_i+t_{i+1}-d_{i+1}$且$S+t_{i+1}-d_{i+1}<S+t_i-d_i$。即调换后$i+1$号任务的超时时间小于调换前$i$号任务的超时时间,调换后$i$号任务的超时时间小于调换前$i+1$号任务的超时时间。那么这两个任务的超时时间的最大值一定比原来的小,而其他任务的超时时间并未改变,也就是经过这样的变换后得到的新解$OPT'' \leq OPT'$。 |
| 144 | + \item 对$OPT'$的序列进行冒泡排序可以得到经过我们贪心策略得到的$OPT$,经过4的推导,我们能得出$OPT \leq OPT'$。故我们的策略正确。 |
| 145 | +\end{enumerate} |
| 146 | + |
| 147 | +\paragraph*{复杂度} |
| 148 | +本算法仍旧是一个对序列某个性质进行排序的算法,时间复杂度为O($nlogn$)。空间复杂度为$O(n)$。 |
| 149 | + |
| 150 | +\section{另一个任调度问题} |
| 151 | +\begin{example} |
| 152 | + 有$n$个任务,每个任务有它的权重$w_i$,以及完成任务需要的时间$t_i$。定义任务$i$的完成时间为$c_i$。要求设置任务的执行顺序使$M = \sum_{i=1}^n {w_ic_i}$最小。 |
| 153 | +\end{example} |
| 154 | + |
| 155 | +\subsection{算法设计} |
| 156 | + |
| 157 | +\paragraph*{贪心策略的选择} |
| 158 | +这道题要贪心的东西有点类似任务的密度,即$\frac{w_i}{t_i}$。一个自然的想法是将$\frac{w_i}{t_i}$大的排在前面。 |
| 159 | + |
| 160 | +\subsection{算法分析} |
| 161 | + |
| 162 | +\paragraph*{贪心策略正确性的证明} |
| 163 | +本例同前一个任务调度的基本思路相同,即证明将逆序的组合($\frac{w_i}{t_i} < \frac{w_{i+1}}{t_{i+1}}$)换成顺序的组合后$M$变小了。 |
| 164 | + |
| 165 | +\begin{enumerate} |
| 166 | + \item 对逆序$(i,i+1)$,假设开始时间为$T_0$,仅对这两项计算代价(调换他们的顺序并不会对前后产生影响)。定义对每一项任务而言代价为$w_ic_i$。 |
| 167 | + \item 进过简单的计算,调换前的代价为$x$,调换之后的代价为$y$。 |
| 168 | + \begin{equation} |
| 169 | + x=(T_0+t_i)w_i+(T_0+t_i+t_{i+1})w_{i+1} |
| 170 | + \end{equation} |
| 171 | + \begin{equation} |
| 172 | + y=(T_0+t_{i+1})w_{i+1}+(T_0+t_i+t_{i+1})w_i |
| 173 | + \end{equation} |
| 174 | + \begin{equation} |
| 175 | + x-y=t_iw_{i+1}-t_{i+1}w_i |
| 176 | + \end{equation} |
| 177 | + \item 我们已知$\frac{w_i}{t_i} < \frac{w_{i+1}}{t_{i+1}}$,由于这四个数都大于0,所以$2.4$式显然成立,故调换顺序后代价小于于原逆序代价。贪心策略正确。 |
| 178 | +\end{enumerate} |
| 179 | + |
| 180 | +\paragraph*{复杂度} |
| 181 | +本算法仍旧是一个对序列某个性质进行排序的算法,时间复杂度为O($nlogn$)。空间复杂度为$O(n)$。 |
0 commit comments