了解常用五大算法

平常都说熟悉基本的数据结构与算法,那么这里这个基本的算法指什么呢,这里就来说一下游戏与算法,从常用的五种算法入手。


分治算法

“分治”二字,就是“分而治之”的意思。把一个比较复杂的问题分成两个相同或相似的子问题,再把子问题分成更小的问题,直到最后,子问题可以简单解决,另外一点就是把所有求得的子问题的解合并就是原复杂问题的解。比如说常用的归并排序、快速排序都是常见的分治思想的体现。

说了分治算法的原理,使用它来解决的问题一般有这几个特征:
1) 问题的规模缩小到一定的程度就可以容易地解决。
2) 问题可以分解为若干个规模较小的相同问题,即问题具有最优子结构性质。
3) 利用问题分解出的子问题的解可以合并为问题的解。
4) 问题所分解出的各个子问题是相互独立的,即子问题之间不包含公共的子问题。

第二条特征是使用分治法的前提,此特征反映了递归思想的应用。
第三条特征是关键,能否利用分治法完全取决于问题是否具有第三条特征,如果具备了第一条和第二条特征,而不具备第三条特征,则可以考虑用贪心法或动态规划法
第四条特征涉及到分治法的效率,如果各子问题是不独立的则分治法要做许多不必要的工作,重复地解公共的子问题,此时虽然可用分治法,但一般用动态规划法较好

所以一些经典问题都可使用分治法求解,这里就列举一些:
(1)归并排序
(2)快速排序
(3)二分搜索
(4)大整数乘法
(5)Strassen矩阵乘法
(6)棋盘覆盖
(7)线性时间选择
(8)最接近点对问题
(9)循环赛日程表
(10)汉诺塔

使用分治方法一般分为三步:
第一步:先找到最小问题规模时的求解方法,一般来说最小问题规模的求解方法是很简单的(归并排序中当问题规模最小的时候,就是只有一个元素的时候,直接就已经有序了)。
第二步:考虑随着问题规模增大时的求解方法。区间划分完了后,开始考虑规模增大之后应该怎么做。
第三步:找到求解的递归函数式后,设计递归程序。


动态规划算法

动态规划算法通常用于求解具有某种最优性质(最大/最小)的问题。这类问题,可能会有许多可行解。每一个解都对应于一个值,但是我们想找到具有最优值的解。动态规划算法与分治算法是相似的,基本思想都是将待求解问题分解成若干个子问题,先求解子问题,然后从子问题的解得到原问题的解。但是又与分治法不同的是,适合于用动态规划求解的问题,经分解得到的子问题往往不是互相独立的,它们是相互关联的。我们可以用一个表来记录所有已解的子问题的答案。不管该子问题的答案以后是否被用到,只要它被计算过,就将其结果填入表中。这就是动态规划法的基本思路。具体的动态规划算法也是多种多样的,但它们具有相同的填表格式。

适用动态规划的问题通常满足最优化原理、无后效性和重叠性这三点。

1)最优化原理:问题的最优解所包含的子问题的解也是最优的,就称该问题具有最优子结构,即满足最优化原理。

2)无后效性:一旦某个阶段的状态确定了,这个状态就不会受到以后决策的影响。也就是说,某状态以后的过程不会影响以前的状态,只与当前状态有关。

3)有重叠子问题:子问题之间不是相互独立的,一个子问题在下一阶段决策中可能被多次使用到。(该性质并不是动态规划适用的必要条件,但是如果没有这条性质,动态规划算法同其他算法相比就不具备优势)

这里就列举一些经典案例:
(1)走台阶
(2)0-1背包
(3)矩阵最小路径合
(4)最长公共子序列

详细看一下走台阶问题

有n级台阶,一个人每次上一级或者两级,问:有多少种走完n级台阶的方法。

动态规划算法实现的关键在于能不能准确合理的用动态规划表来抽象出实际问题。

我们用 dp[n] 来表示动态规划表,dp[i] 表示到达 i 级台阶的方法数(0<i<=n)。

n为1时,dp[n] = 1;
n为2时,dp[n] = 2;
那么当我们要走上n级台阶,必然是从n-1级台阶迈一步,或者是从n-2级台阶迈两步。所以到达n级台阶的方法数必然是到达n-1级台阶的方法数加上到达n-2级台阶的方法数之和。即 dp[n] = dp[n-1] + dp[n-2]

public class CalculationSteps {

    //动态规划表step[n],用来记录到达i级台阶的方法数
    public static int[] steps = new int[11];

    //计算到达i级台阶的方法数
    public static int calStep(int n){
        if(n==1 || n==2)     return n;
        if(steps[n-1]==0)    steps[n-1] = calStep(n-1);   //计算到达n-1级台阶的方法数
        if(steps[n-2]==0)    steps[n-2] = calStep(n-2);   //计算到达n-2级台阶的方法数
        return steps[n-1] + steps[n-2];
    }
    
    public static void main(String[] args) {
        steps[10] = calStep(10);
        for (int i = 0; i < steps.length; i++) {
            System.out.print(steps[i]+" ");
        }
    }
}

运行结果:
0 1 2 3 5 8 13 21 34 55 89

这里有几篇参考博文, 文A文B文C


贪心算法

贪心算法是指:在每一步的求解中,做出最为有利的选择,并希望通过一系列的最优选择,能够产生一个问题的最优解。也就是说它不从整体上考虑,它只是做出了某种意义上的局部最优解。

贪心算法每一步必须满足一下条件:
1.可行的:即它必须满足问题的约束。
2.局部最优:他是当前步骤中所有可行选择中最佳的局部选择。
3.不可取消:即选择一旦做出,在算法的后面步骤就不可改变了。

它一般有这些步骤:
第一步:通过建立数学模型来描述问题。
第二步:把求解的问题分成若干个子问题。
第三步:对每一子问题求解,得到子问题的局部最优解。
第四步:把子问题的局部最优解合成原来问题的一个解。

跟它有关的常见问题有:
(1)寻路问题
(2)活动选择问题
(3)最小生成树


回溯算法

回溯算法是类似枚举的搜索过程,在这个搜索过程之中寻找问题的解,当发现不满足求解条件的时候,就会回溯返回,去尝试别的方向。

比如解迷宫问题就可以使用回溯算法。它还可以说是一种优选搜索法,按照选优条件向前搜索,以求达到最终的目标。在迷宫问题中,等到达出口的时候,那么回溯的过程也就结束了。但是在这个逐步前进的过程之中,发现原先的选择并不是最优或者说是根本到不了目的地,碰到了障碍物,那么这时候它就会退回一步去重新选择,这种回退一步的方法就是回溯算法,满足回溯状态的某个点被称之为回溯点。

接下去再来说一说回溯法的核心思想,在包含所有问题的解空间树之中,按照深度优先搜索的策略,从根节点出发深度搜索解空间树。当搜索到某一个节点的时候,需要先判断该节点是否包含问题的解,换句话说检测当前点是否满足条件。如果包含或者说是满足条件,那么就从该节点出发继续搜索下去,如果该节点不包含所求问题的解,那么就逐层向其祖先节点进行回溯!说到这里可能大家也会感觉到其实也就是我们常说的深度优先策略,我们学习图的过程之中经常会使用到深度优先和广度优先的策略!因此对于这种策略也不会陌生,按照这种策略,首先从根节点出发深度搜索解空间树。当搜索到某一个节点的时候,这时候需要判断该节点是否包含问题的解,如果包含,就从该节点继续出发搜索下去,如果该节点不包含问题的解,那么这时候就逐层向根节点进行回溯。

其实所谓的回溯算法就是对隐式图的深度优先搜索算法。

若用回溯算法求解问题的所有解的时候,如果没有找到最终的目标,那么只有当回溯到根节点的时候才可以,并且根节点的所有可行子树都要已被遍历才可以。但是通常我们只需要某一个解就行了,比如在走迷宫的时候我们只需要找到一个出口就行了(假设迷宫有多个出口)。

参考博文, 这里


分支界限算法

它和回溯算法比较相似,也是一种在问题的解空间树上来搜索问题解的算法。分支界限算法与回溯算法的求解目标不同,回溯算法是找出树中满足约束条件的所有解,一般来说只是用了其中的一个解。分支界限算法是找出满足约束条件的一个解,或是在满足约束条件的解中找出使某一目标函数达到最大或最小的解,即在某种意义下的最优解。

其实分支界限算法执行的是广度优先策略。
具体来说,在扩展结点处,先生成其所有的儿子结点(分支),然后再从当前的活结点列表中选择下一个扩展结点。为了有效地选择下一个扩展结点,以加速搜索的进程,在每一活结点处,计算出一个函数值(限界),并根据这些已计算出的函数值,从当前活结点列表中选择一个最有利的结点作为扩展结点,使搜索朝着解空间树上有最优解的分支推进,以便尽快地找出一个最优解。

分支限界法常以广度优先或以最小耗费(最大效益)优先的方式搜索问题的解空间树。问题的解空间树是表示问题解空间的一棵有序树,常见的有子集树和排列树。在搜索问题的解空间树时,分支限界法与回溯法对当前扩展结点所使用的扩展方式不同。在分支限界法中,每一个活结点只有一次机会成为扩展结点。活结点一旦成为扩展结点,就一次性产生其所有子结点。在这些子结点中,那些导致不可行解或导致非最优解的子结点将被舍弃,其余子结点被加入活结点列表中。此后,从活结点列表中取下一结点成为当前扩展结点,并重复上述结点扩展的过程。这个过程一直持续到找到所求的解或活结点列表为空时停止。


未完待续…2019.3.15

猜你喜欢

转载自blog.csdn.net/THIOUSTHIOUS/article/details/88354389