算法复习

一、主方法求解递归方程

主方法提供以下形式递归方程的一般方法

T(n) = aT(n/b) + f(n)

满足:

情况1)函数nlogba比函数f(n)大,则T(n) = O(nlogba)

情况2)函数nlogba和函数f(n)一样大,则T(n) = O(nlogba·log2n)

情况3)函数nlogba比函数f(n)小,则T(n) = O(f(n))

二、状态空间树

 递归回溯框架-----回溯法

解空间为子集树和排列树

子集树

递归回溯框架

int x[n];                                       //x存放解向量,为全局变量

void backtrack(int i)                         //求解子集树的递归框架
{
if(i> n)        //搜索到叶子结点,输出一个可行解
输出结果;
else
{
for(j=下界;j<=上界;j++)              //用j枚举i所有可能的路径
{
x[i]
=j;        //产生一个可能的解分量
..        //其他操作
if (constraint(i) & &. bound(i))
backtrack(i
+ 1);           //满足约束条件和限界函数,继续下一层 }
}
}

例:有一个含n 个整数的数组a .所有元素均不相同,设计一个算法求其所有子集(幂集)。例如a[]={1.2.3},所有子集是{}、{3}、{2}、{2,3}、{1}、{1,3}、{1,2}、{1,2,3}(输出顺序无关)。

# include <stdio.h>
# include <string.h>
# define MAXN 100
void dispasolution(int a[] , int n, int x[])  
{
    printf(" {");
    for (int i=0;i<n;i++ )
        if (x[i]==1)
            printf("%d",a[i]);
    printf("}");
}
void dfs(int a[],int n, int i, int x[])  
{
    if (i >= n )
        dispasolution(a, n,x );
    else
    {
        x[i]=0;dfs(a,n,i+1,x);
        x[i]=1;dfs(a,n,i+1,x);  
    }
}

int main( )

{
    int a[]={1,2,3};
    int n= sizeof( a)/ sizeof(a[0]);
    int x[MAXN];    
    memset(x,0, sizeof(x));
    printf("求解结果\n");
    dfs(a,n,0,x);
    printf("\n");
    return 0;
}

图示

 

排列树

 递归回溯框架

int x[n];                       //x存放解向量,并初始化

void backtrack(int i)           //求解排列树的递归框架

{
    
    if(i> n)                    //搜索到叶子结点,输出一个可行解

        输出结果;

    else

    {
        
        for(j=i;j<=n;j++)       //用j枚举i的所有可能路径

        {
            ..                  //第i层的结点选择x[j]的操作

            swap(x[i],x[j] );   //为保证排列中的每个元素不同,通过交换来实现

            if (constraint(i) &. & bound(i))

                backtrack(i+ 1);//满足约束条件和限界函数,进入下一层

            swap(x[i],x[i]);    //恢复状态

            ..                  //第i层的结点选择x[j]的恢复操作
        }

    }
    
}

例:有一个含n个整数的数组a,所有元素均不相同,求其所有元素的全排列。例如,a[]={1,2,3},得到的结果是(1,2,3)、(1,3,2)、(2,3,1)、(2,1,3)、(3,1,2)、(3,2,1)。

图示:

 

三、状态转移方程

 

四、算法概念

算法重要特征:有限性(有限步骤)、确定性(不会产生二义性)、可行性(可以被分解为基本的可执行的操作步,即每个计算步都可以在有限时间内完成)、输入性、输出性(至少一个)

时间复杂度:

递归

定义:在函数的定义中又调用函数自身的方法

思想:把一个大型复杂的问题层层转化为一个或多个与原问题相似的规模较小的问题来求解。

特征:

1、需要解决的问题可以转化为一个或多个子问题来求解,而这些子问题的求解方法与原问题完全相同,只是在数量规模上不同。

2、递归调用的次数必须是有限的。

3、必须有结束递归的条件来终止递归。

使用场合:

1. 定义是递归的

 有许多数学公式、数列等的定义是递归的。例如,求n! 和Fibonacci 数列等。

2. 数据结构是递归的

数据结构是递归的。例如单链表就是一种递归数据结构

3. 问题的求解方法是递归的

 有些问题的解法是递归的,典型的有Hanoi问题

分治

思想:

若该问题可以容易地解决(比如说规模n 较小)则直接解决,否则将其分解为k 个规模较小、互相独立、与原问题类型相同的子问题,递归地解这些子问题,然后将各子问题的解合并得到原问题的解。

特征:

规模较小、互相独立、形式相同的子问题

适用场所:

(1 )该问题的规模缩小到一定的程度就可以容易地解决。

(2 )该问题可以分解为若干个规模较小的相似问题。

(3 )利用该问题分解出的子问题的解可以合并为该问题的解。

(4 )该问题所分解出的各个子问题是相互独立的,即子问题之间不包含公共的子问题。

策略:

① 分解: 将原问题分解为若干个规模较小,相互独立,与原问题类型相同的子问题。

② 求解子问题:若子问题规模较小而容易被解决则直接求解,否则递归地求解各个子问题。

 ③ 合并:将各个子问题的解合并为原问题的解。

一些排序算法的时间复杂度:

 快速排序:O(n) 最好O(nlog2n) 最坏O(n2)  核心部分是划分操作

随机过程避免算法最坏情况的发生

 

归并排序(二路归并排序算法):O(nlog2n)

     二路合并排序算法是最优算法

 折半查找:O(log2n)

蛮力

思想:

 对问题的所有可能状态一一测试,直到找到解或将全部的可能状态都测试为止

特征:

第一,可以解决的问题类型广泛

第二,可以解决小规模的问题

第三,逻辑清晰,编写程序简洁

第四,对一些重要问题,可以产生一些合理算法。

第五,效率不高,但是可以作为其他高效算法的衡量标准。

适用于:

1、搜索所有的解空间 :问题的解存在于规模不大的解空间中。

2、搜索所有的路径 :这类问题中不同的路径对应不同的解。

3、直接计算 :按照基于问题的描述和所涉及的概念定义,直接进行计

算。往往是一些简单的题,不需要算法技巧的。

4、模拟和仿真

回溯

思想:

是一个类似穷举的搜索尝试过程,主要是在搜索过程尝试寻找问题的解,当发现已不满足求解条件时就回退,尝试其他路径

特征:

深度搜索加回退

适用于:

1、求所有解,或者一个解

2、求最优解

搜索策略:

 

分枝限界

思想

在每次分支后,对凡是界限超出已知可行解值那些子集不再做进一步分支。从而缩小了搜索范围。这一过程一直进行到找出可行解或者存放活节点的队列为空为止,

特征:

一般使用队列或优先队列存放活节点表,搜索停止的条件是找到一个解或者队列为空

适用于:

找出满足条件一个解或者特定意义的最优解

关键问题:1.确定合适的限界函数

                2.组织待处理结点的活结点表

                3.确定解向量的各个分量

回溯和分支限界的异同:

相同点:

都在问题的状态空间树上搜索问题解,都通过活结点表实现。都用到剪枝函数,约束函数剪去不含答案的分枝,限界函数剪去不含最优解的分枝。

不同点:

  1. 搜索方式:回溯法是深度优先,分支限界法是广度优先
  2. 存储节点的数据结构不同:回溯法是栈(后入先出),分支限界法是队列和优先队列
  3. 结点的扩展方式不同:回溯法中活结点的所有可行子结点都遍历后才会出栈(可能多次成为扩展结点),分支限界法中每个结点只能成为一次扩展结点
  4. 求解目标:回溯法求解满足条件的所有解,分支限界法求解满足条件的一个解或特定意义的最优解

贪心

思想(是解决问题的思想,不是具体算法)

贪心法的基本思路是在对问题求解时总是做出在当前看来是最好的选择,也就是说贪心法不从整体最优上加以考虑,所做出的仅是在某种意义上的局部最优解。

特征:

 只从局部根据某种条件考虑当前局部的最优解

贪心准则(最优量度标准):每一步用作决策依据的选择准则

含有以下两个性质:

1、贪心选择性质:整体的最优解通过一系列局部最优解的选择达到;

2、最优子结构:一个问题的最优解包含其子问题的最优解

搜索策略:

 

完全背包问题:最优度量标准:权重比

哈夫曼树:       最优度量标准:带权外路径长度最小

动态规划

思想:

       基于一个递推公式及一个或多个初始状态,当前子问题的解由上一次子问题的解推出

动态规划是一种解决多阶段决策问题的优化方法,把多阶段过程转化为一系列单阶段问题,利用各阶段之间的关系,逐个求解。

特征:

最优子结构;

无后效性;

重叠子问题(可无)(动态规划思想的优势之处)

适用场所:

存在最优子结构性质

搜索策略:

①    分析最优解的性质,并刻画其结构特征。

②     递归的定义最优解。

③     以自底向上或自顶向下(备忘录)的记忆化方式计算出最优值。

④     根据计算最优值时得到的信息,构造问题的最优解。

与其他算法的区别:

分治法的子问题不重叠;

贪心法的每次决策不可回溯,需要考察每个序列是否包含最优子序列

ps:动态规划是自底向上的,递归是自顶向下,备忘录是自顶向下的,由动态规划变形的

五、算法实验

算法实验

posted @ 2021-12-17 15:31  makonyan  阅读(405)  评论(0)    收藏  举报
Live2D