算法策略

活动选择问题

活动选择问题问题可表述为“设\(S[0,1…n]\)为‘活动’的序列,每个‘活动’有开始、结束时间,\(S\)已按结束时间升序排序。规定所有‘活动’独占同一个教室,求出\(S\)中的‘活动’最多能安排多少个”。上图是其中一种\(S\)的例子。 设\(L\)是一个最优活动安排序列(已排序)。任取\(L[k]\),并用其划分序列\(L_1 = L[0,…,k-1],L_2=L[k+1,…]\)。然后设\(s_1\)是“\(L[k]\)开始前结束的\(S\)中的所有活动”,\(s_2\)是“\(L[k]\)结束后开始的\(S\)中的所有活动”。可发现如果把\(s_1,s_2\)作为原问题的输入,则\(L_1,L_2\)必可分别作为最优活动安排序列,否则\(L\)本身就不是原问题的最优解了。然后任取\(L_1[k_1]\)……可以发现上述结论是递归的。然后用这个性质去找最优解,先回到原问题上,其任意最优活动安排序列都符合“空序列,包含\(S[0]\),包含\(S[1]\),包含\(S[2]\)…”中的至少一种,如果符合的是空序列,那么解就是0,否则就遍历这些元素,设每次遍历到的元素是\(x\),然后用其划分\(S\)为“\(x\)开始前结束的\(S\)中的所有活动”,“\(x\)结束后开始的\(S\)中的所有活动”这两个序列,然后分别递归的求出它们的解并计做\(c_1,c_2\),然后求出\(c=c_1+1+c_2\),即放入\(x\)后的总活动数。每次遍历都会求一次\(c\),其中最大的那个就是解。… 阅读全文

哈夫曼编码

字符编码编码指把相同信息在不同的形式间转化,例如把图片储存为像素(x,y,r,g,b),把直角坐标方程改写为极坐标方程,把26个字母用26个二进制数表示,把明文转为密码和密文等等。无论信息形式如何变化,它们依然是同样的信息。字符编码研究如何用二进制形式表示某种语言的字符,其可被分类为定长编码与变长编码。基础ASCII码是种定长编码,无论是英文逗号、空格、回车、换行甚至响铃都有自己的ASCII码。其定长策略是在所有二进制数(编码)前补0,保证每个编码都是7-Bit。强国官方编码GB18030是种变长编码,其有1/2/4字节三种长度,1字节长度的是ASCII的超集,2字节长度的是GBK的超集,4字节长度的是其他新加入的生僻的中文字符与中文符号。   前缀编码对任意字符串的任意前缀编码方案,每个字符的编码都不是其他编码的前缀。任何前缀编码方案都可用二叉树(如上图)表示,其非叶节点的左/右边表示0/1,从根节点出发可根据编码方案“生成”编码树。由于前缀码间互不为前缀,故字符不会出现在非叶节点,故叶节点必为被编码字符本身。对字符串\(S\)与其前缀编码二叉树\(T\),设\(f(c)\)为字符\(c\)的出现次数,\(d(c)\)为字符\(c\)在前缀编码二叉树的深度,编码二叉树所对应的代价为\(B(T)=\sum… 阅读全文

拟阵理论与通用贪心算法

拟阵的定义 拟阵(Matroid)一词最早于1935年被数学家Whitney使用,其是从矩阵的线性无关概念中提炼而来的,拟阵多种不同的等价定义,其基于子集系统的定义如下,第1~4定义了子集系统,拟阵是满足交换性质的子集系统: 1) 拟阵\(M\)是为二元组\((S,L)\); 2) \(S\)是有限集合; 3) \(L\)是由\(S\)的符合下述性质的子集组成的有限非空集; 4) 遗传性质:对任意\(B\in L\)与\(A\subseteq B\),都满足\(A\in L\); 5) 交换性质:对任意\(A\in L\)与\(B\in L\)。若\(|A|<|B|\),则存在\(x \in B-A\),使\(A\bigcup\{x\} \in L\); 在无向图\((V,E)\)上可定义图拟阵(Graphic Matroid),图拟阵与拟阵等价,故图拟阵也可定义拟阵:… 阅读全文

拟阵下的单位时间任务调度问题

问题描述 单位时间任务的最优调度问题的原型是操作系统在单核CPU上的调度,其需要的输入信息如下。问题的目标是找到\(S\)的一个调度(排序),可以使得超过截止时间后的总惩罚值最小。 1) \(n\)个单位时间(耗费时间为1)任务的集合\(S=\{a_1,a_2…\} \); 2) \(n\)个整数的期望的截止时间\(\{d_1,d_2…\} \),显然\(1 \leq d_i \leq n\); 3) \(n\)个非负的惩罚值\(\{w_1,w_2…\} \); 在讨论问题前,预先给出更进一步的定义与相关性质如下: 1) 提前任务:任务在某个调度的截止时间前完成,称该任务为该调度的提前任务; 2) 延迟任务:任务在某个调度的截止时间后完成,称该任务为该调度的延迟任务; 3) 提前优先调度:任意调度可在总惩罚值不变时,把所有提前任务排在延迟任务前;… 阅读全文

动态规划

动态规划 20世纪50年代初,美国数学家R.Bellman等在创立了动态规划(Dynamic Programming),用于解决多阶段决策过程的问题。所以动态规划最早是应用数学、运筹学中的概念,并非算法概念。在用动态规划策略解决问题时,解题者需要先把问题拆分成有序的多个“阶段”,这些“阶段”的“形式”通常一样。后面的“阶段”的解可以根据前面若干个不同“阶段”的解来确定,但不能被更后面的“阶段”的解所决定(这也称为无后效性)。这种关系需要被描述成通常包含递推函数的“状态转移方程”。借助状态转移方程,就能依次得到每个“阶段”的解,最终得到问题的解。可以发现,“阶段”就类似分治法中的“子问题”,“状态转移方程”就类似解决“子问题”的递归程序,所以动态规划和分治法的策略框架基本一样,也可能分治法外延更广一点。… 阅读全文

(01)背包问题

(01)背包问题 之前讨论过该问题的一种分治算法,这里讨论一种更优的DP(动态规划)算法,其沿用之前的子问题划分思路,依赖数值的递推关系。先定义函数\(F(k,V)\)为“体积\(V\)的背包与物品前\(k+1\)项子序列\([t_0…t_k]\)能取到的最大总价值”。根据在分治法的讨论,可得\(F\)的递推式\(F(k,V) = max\{ F(k-1,V-A_k)+B_k, F(k-1,V) \} \),该式也称为状态转移方程。需要注意其边界情况,\(V-A_k<0\)时说明物品本身的体积就超过背包容积,此时\(F(k,V)=F(k-1,V)\)。另一个边界情况是序号取-1时,显然有\(F(-1,V)=0\)。此时等于找到了最大总价值的递推关系,而不是解本身的递推关系。 然后是求\(F(k,V)\),这里不用分治法“自顶向下递归”的方式,而是用“自底向上迭代”的方式。先初始化二维序列\(F[x][y]\),然后从\(F[0][0]\)开始计算出每个下标对应的值,直到得出\(F[k][V]\)本身。这是DP中常用的计算方式,其相比函数递归,能避免对同一输入的多次计算,其缺点是需要建立维护数组,也会计算一部分之后用不上的值。… 阅读全文

二维(01)背包问题

二维(01)背包问题 其可描述为“设物品序列中每个物品只有1个,物品\(i\)有2个费用属性\(x_i,y_i\),有1个价值属性\(w_i\)。给定2个正整数\(U,V\),求物品组合使\(\sum x_k \leq U \)与\(\sum y_k \leq V \)时,\(\sum w_k\)最大”。形象一点来说就是背包除了体积限制,还有重量限制。 问题的状态转移方程是\(F(i,u,v) = max\{~ F(k-1,u-x_i,v-y_i)+w_i, F(k-1,u,v) ~ \} \),参考(01)背包的思路很容易找到和证明该方程。问题的一个边界是\(u-x_i<0\)或\(v-y_i<0\)取\(F(i,u,v) = F(k-1,u,v) \)。下面给出用动态规划求解出\(F(i,u,v)\)的步骤,并且不讨论如何用求出来的\(F\)得到具体解。… 阅读全文

物品分组(01)背包问题

物品分组(01)背包问题 该问题是在(01)背包问题上附加条件“所有物品一开始被划入了几个不相交的物品组,且每组只能从中取其中一个”。这里不妨规定物品组也以序列给出,而每个物品组又都是1个物品序列。这里稍微改下\(F(k,V)\)的定义为“体积\(V\)的背包与物品组前\(k+1\)项子序列能取到的最大总价值”,即\(k\)是关于物品组的。 列出状态转移方程\(F(k,V) =max\{~F(k-1,V),~max\{ F(k-1, V-A_{k,i}) + B_{k,i} | i\in [0,|A_k|-1] \}~  \} \),\(i\)是当前物品分组中的物品下标,\(A,B\)按二维数组(物品分组下标,物品下标)提供。得到方程的思路跟其他背包问题相似,这里略去讨论。要注意边界情况的处理,\(V-A_{k,i}<0\)时应直接剔除,不参与求\(max\)。这里同样略去通过\(F\)得到具体解的步骤。… 阅读全文

完全背包问题与多重背包问题

完全背包问题与多重背包问题 完全背包问题的描述是“给定容积为\(V\)的背包与物品序列,物品\(i\)的价值与体积分别为\(A_i,B_i\)。设序列中每个物品有无限个可以取,如何取物品可使总价值最大”。《算法导论》中的钢条切割问题就是完全背包问题。 这个问题本身可以转化成(01)背包问题,虽然每种物品有无限个,但背包容量却是有限的,故对于物品\(i\),其至多能被取\(\lfloor{V/B_i}\rfloor\)次(其中\(\lfloor \rfloor\)表示向下取整,即直接丢弃小数点后的数),从无限变为有限后就很好处理了,只需要把这些一样的物体“平铺”开就能得到一个新的物品序列,然后用这个新的物品序列求解对应的(01)背包问题即可。 按上述思路可得状态转移方程\(F(k,V)=max\{~ F(i-1,V-mB_i)… 阅读全文

最大连续子序列问题

最大连续子序列 之前讨论过该问题的一种分治算法,这里讨论基于另一种划分子问题策略的DP算法。设原数组\(L=[i_0,i_1,…,i_n]\),函数\(F(k)\)为“\(L\)中以\(i_k\)结尾的全部连续子数组的元素值之和中的最大值”,则\(F(k)\)满足方程“\(F(k+1) = max\{ F(k) + L[k+1], L[k+1] \}\),且\(F(0)=L[0]\)”。若解出\(F(0),F(1),..,F(n)\),求出其中最大值即得原问题的解。该求解过程的编程实现通常是这样,先定义数组\(F[k]\)表示\(F(k)\),从\(F[0]\)开始自低向高以数组递推并记录\(F[k]\)所有值,最后求数组\(F[k]\)的最大值即为解。算法代价为\(O(n)\)。 上述分析与解决问题的方法就是动态规划,其中关于\(F(k)\)的方程被称为动态规划的状态转移方程。该动态规划算法的代码既简短也易理解,但其实该问题本身并不特别简单,最大子数组问题最早于1977年提出,但直到1984年才被卡内基梅隆大学的教授Jay… 阅读全文
滚动至顶部