算法设计与分析基础

问题求解的关键

  1. 问题建模

    对输入参数和解给出形式化或半形式化的描述

  2. 设计算法

    选择什么算法?如何描述这个方法?

    这个方法是否对所有实例都得到正确的解?如何证明?

    如果不是,能否找到反例?

  3. 分析算法

    分析算法的效率

NP难问题

  • NP-hard问题有数千个,大量存在于各个应用领域。NP-hard问题举例:TSP问题、0-1背包、双机调度
  • 目前还没有找到有效算法,有效算法指的是运行时间是输入规模$n$的指数或更高阶函数,即输入规模$n$的多项式时间。
  • 至今没有人能证明这类问题不存在多项式时间的算法。
  • 从是否存在多项式时间算法的角度来看,这些问题是彼此等价的(如果其中一个问题存在多项式时间的算法,则其它问题也都存在;如果其中一个不存在,则其它问题也不存在多项式时间算法)。这些问题的难度处于可有效计算的边界。

问题

定义

需要回答的一般性提问,通常含若干参数

问题描述

  • 定义问题参数(可以是集合、变量、函数、序列等等)
  • 说明每个参数的取值范围和参数间的关系
  • 定义问题的解
  • 说明解满足的条件(优化目标或约束条件)

问题实例

参数的一组赋值可得到问题的一个实例

算法

定义

有限条指令的序列,这个指令序列确定了解决某个问题的一系列运算或操作。

要求

若算法A解问题P,则应满足:

  • 把问题P的任何实例作为算法A的输入,都可输出该实例的正确解
  • 每步计算是确定性的
  • A能够在有限步停机

基本运算

可以是比较、加法、乘法、置指针、交换等等操作。

基本运算的确定往往和输入规模相关,算法基本运算的次数可表示为输入规模的函数。

  • 排序

    元素之间的比较

  • 检索

    被检索元素$x$与数组元素的比较

  • 整数乘法

    每位数字相乘(位乘)1次,$m$位和$n$位整数相乘要做$mn$次位乘

  • 矩阵相乘

    每对元素乘1次

    $i\times j$矩阵与$j\times k$矩阵相乘要做$ijk$次乘法

  • 图的遍历

    置指针

时间复杂度

针对指定的基本运算,算法所做基本运算的次数。

对于相同输入规模的不同实例,算法的基本运算次数也不一样,我们可定义以下两种时间复杂度。

  • 最坏情况下的时间复杂度$W(n)$

    算法求解输入规模为$n$的实例所需要的最长时间

  • 平均情况下的时间复杂度$A(n)$

    在给定同样规模为$n$的输入实例的概率分布下,算法求解这些实例所需要的平均时间

    设$S$是规模为$n$的实例集,实例$I\in S$的概率是$P_I$,算法对实例$I$执行的基本运算次数是$t_I$,则$A(n)=\sum_{I\in S}P_It_I$

输入规模

通常用数组元素多少、调度问题的任务个数、图的顶点数和边数等表示

  • 排序

    数组中元素个数$n$

  • 检索

    被检索数组的元素个数$n$

  • 整数乘法

    两个整数的位数$m$和$n$

  • 矩阵相乘

    矩阵的行列数$i,j,k$

  • 图的遍历

    图的顶点数$n$,边数$m$

  • 给定问题和基本运算就决定了一个算法类

    比如排序问题,以元素间的比较为基本运算,就确定了一个算法类。

伪码描述

  • 赋值语句

    $\leftarrow$

  • 分支语句

    if…then..…[else..…]

  • 循环语句

    while,for,repeat,until

  • 转向语句

    goto

  • 输出语句

    return

  • 调用

    直接写过程的名字

  • 注释

    //..…


作者:@臭咸鱼

转载请注明出处:https://chouxianyu.github.io

欢迎讨论和交流!