第10篇 ACM/ICPC竞赛之算法策略算法
ACM/ICPC竞赛其实就是算法设计和编码的竞赛,熟悉各类经常使用算法和算法设计策略并能灵活运用是很是必要的。
这里对几种在竞赛中常常用到的算法设计策略作一简单的介绍。
1、穷举法
穷举法是最基本的算法设计策略,其思想是列举出问题全部的可能解,逐一进行判别,找出知足条件的解。
穷举法的运用关键在于解决两个问题:
如何列举全部的可能解;
如何判别可能解是否知足条件;
在运用穷举法时,容易出现的问题是可能解过多,致使算法效率很低,这就须要对列举可能解的方法进行优化。
以题hduoj 1041--纯素数问题为例,从1000到9999均可以看做是可能解,能够经过对全部这些可能解逐一进行判别,找出其中的纯素数,但只要稍做分析, 就会发现其实能够大幅度地下降可能解的范围。根据题意易知,个位只多是3、5、7,再根据题意可知,能够在3、5、7的基础上,先找出全部的二位纯素 数,再在二位纯素数基础上找出三位纯素数,最后在三位纯素数的基础上找出全部的四位纯素数。
2、分治法
分治法也是应用很是普遍的一种算法设计策略,其思想是将问题分解为若干子问题,从而能够递归地求解各子问题,再综合出问题的解。
分治法的运用关键在于解决三个问题:
肯定分治规则,即如何分解问题。
肯定终结条件,即问题分解到什么状态时能够直接求解。
肯定概括方法,即如何由子问题的解获得原问题的解。这一步并不老是须要的,由于对某些问题来讲,并不须要对子问题的解进行复杂的概括。
咱们熟知的如汉诺塔问题、折半查找算法、快速排序算法等都是分治法运用的典型案例。
以题hduoj 1045--Square Coins为例,先对题意进行分析,可设一个函数f(m, n)等于用面值不超过n2的货币构成总值为m的方案数,则容易推导出:
f(m, n) = f(m-0*n*n, n-1)+f(m-1*n*n, n-1)+f(m-2*n*n, n-1)+...+f(m-k*n*n, n-1)
这里的k是币值为n2的货币最多能够用多少枚,即k=m/(n*n)。
也很容易分析出,f(m, 1) = f(1, n) = 1
对于这样的题目,一旦分析出了递推公式,程序就很是好写了。因此在动手开始写程序以前,分析工做作得越完全,逻辑描述越准确、简洁,写起程序来就会越容易。
3、动态规划法
动态规划法多用来计算最优问题,动态规划法与分治法的基本思想是一致的,但处理的手法不一样。动态规划法在运用时,要先对问题的分治规律进行分析,找出终结子问题,以及子问题向父问题概括的规则,而算法则直接从终结子问题开始求解,逐层向上概括,直到概括出原问题的解。
动态规划法多用于在分治过程当中,子问题可能重复出现的状况,在这种状况下,若是按照常规的分治法,自上向下分治求解,则重复出现的子问题就会被重复地求 解,从而增大了冗余计算量,下降了求解效率。而采用动态规划法,自底向上求解,每一个子问题只计算一次,就能够避免这种重复的求解了。
动态规划法还有另一种实现形式,即备忘录法。备忘录的基本思想是设立一个称为备忘录的容器,记录已经求得解的子问题及其解。仍然采用与分治法相同的自上 向下分治求解的策略,只是对每个分解出的子问题,先在备忘录中查找该子问题,若是备忘录中已经存在该子问题,则不须再求解,能够从备忘录中直接获得解, 不然,对子问题递归求解,且每求得一个子问题的解,都将子问题及解存入备忘录中。
例如,在题1045--Square Coins中,能够采用分治法求解,也能够采用动态规划法求解,即从f(m, 1)和f(1, n)出发,逐层向上计算,直到求得f(m, n)。
在竞赛中,动态规划和备忘录的思想还能够有另外一种用法。有些题目中的可能问题数是有限的,而在一次运行中可能须要计算多个测试用例,能够采用备忘录的方 法,预先将全部的问题的解记录下来,而后输入一个测试用例,就查备忘录,直接找到答案输出。这在各问题之间存在父子关系的状况下,会更有效。例如,在题 hduoj 1045--Square Coins中,题目中已经指出了最大的目标币值不超过300,也就是说问题数只有300个,并且各问题的计算中存在重叠的子问题,能够采用动态规划法,将 全部问题的解先所有计算出来,再依次输入测试用例数据,并直接输出答案。
4、回溯法
回溯法是基于问题状态树搜索的求解法,其可适用范围很广。从某种角度上说,能够把回溯法看做是优化了的穷举法。回溯法的基本思想是逐步构造问题的可能解, 一边构造,一边用约束条件进行判别,一旦发现已经不可能构造出知足条件的解了,则退回上一步构造过程,从新进行构造。这个退回的过程,就称之为“ 回溯”。
回溯法在运用时,要解决的关键问题在于:
如何描述局部解。
如何扩展局部解和回溯局部解。
如何判别局部解。
回溯法的经典案例也不少,例如全排列问题、N后问题等。
5、贪心法
贪心法也是求解最优问题的经常使用算法策略,利用贪心法策略所设计的算法,一般效率较高,算法简单。贪心法的基本思想是对问题作出目前看来最好的选择,即贪心选择,并使问题转化为规模更小的子问题。如此迭代,直到子问题能够直接求解。
基于贪心法的经典算法例如:哈夫曼算法、最小生成树算法、最短路径算法等。
可是,贪心法的运用是有条件的,必须可以证实贪心选择可以导出最优解,且转化出的子问题与原问题是同性质的问题,才能使用贪心法求解。
一个比较经典的贪心法求解的问题就是找硬币问题:有1、2、5、10、20、50、100七种面值的硬币,要支付指定的金额,问怎么支付所用的硬币个数最 少。这是一个很是平常化的问题,凭直觉咱们会想到,尽量先用大面值的硬币,这就是“贪心选择”,而在这个问题上,这个贪心选择也是正确的。
6、限界剪枝法函数
限界剪枝法是求解较复杂最优问题的一种算法策略,与回溯法相似的是,限界剪枝法也是在问题状态空间树上进行搜索,但回溯法是搜索通常解,而限界剪枝法则是 搜索最优解。限界剪枝法的基本思想是经过找出权值函数的上下界函数,如下界函数来指导搜索的方向,以上界函数来帮助剪除一些不可能含有最优解的分枝。
关于算法和算法策略的讨论是一个很是庞大的话题,几乎每一个问题点都能扩展出一大堆可讨论的内容和案例。我实在不知道该怎样用简短的几篇文字就可以把这个话题说透,这里只能走马观花地对竞赛中常常用到的几种策略作一极为简略的介绍。
也许咱们能够在之后的文章中,针对具体的题目进行算法和策略的分析,效果可能会更好。测试
未完待续###优化