sfqm

2.算法

什么是算法?算法的四条的性质    

•算法是指解决问题的一种方法或一个过程。

•算法是若干指令的有穷序列,满足性质:输入,输出,确定性,有限性

算法复杂性的表示方法

•算法复杂性= 算法所需要的计算机资源

•算法的时间复杂性T(n);

•算法的空间复杂性S(n)。

•其中n是问题的规模(输入大小)。

OΩθ的含义。

1)渐近上界记号O 最坏复杂度

2)渐近下界记号Ω 最优复杂度

3)紧渐近界记号θ界定函数的渐进上下界

最坏情况下的复杂度; 平均时间复杂度; 它们的实际意义是什么

最坏情况下的时间复杂度是算法在任何输入实例上运行时间的上界。平均时间复杂度是指所有可能的输入实例均以等概率出现的情况下,算法的期望运行时间。

3.递归与分治策略

什么是递归?直接递归;间接递归

直接或间接地调用自身的算法称为递归算法。

直接调用自己,即在函数中调用函数自身或者在过程的子部分中调用子部分自身的内容

间接调用自己,即不同的函数和子过程之间互相调用

分治:二分搜索;归并排序;快排;

分治法基本思想:将一个规模为n的问题分解为看个规模较小的问题,这些问题相互独立且与原问题相同。

解题步骤:分解→求解→合并

二分搜索: 

template int BinarySearch(Type a[], const Type& x, int l, int r)   l是左边界索引,r是有边界索引  循环的条件是右边界索引大于

{                                                   左边界索引。一半一半的找。

while (r >= l){

int m = (l+r)/2;

if (x == a[m]) return m;

 if (x < a[m]) r = m-1;

 else l = m+1;

}

return -1;

}

 

归并排序:MERGE_SORT(A,p,r)

    if p<r

        q=floor((p+r)/2)

        MERGE_SORT(A,p,q)//左排序

        MERGE_SORT(A,q+1,r)//右排序

        MERGE(A,p,q,r) //合并

end

快速排序:QuickSort(A,p,r)

       if p<r

            q = Partition(A,p,r)    //确定划分位置

            QuickSort(A,p,q-1)     //子数组A[p...q-1]

            QuickSort(Q,q+1,r)     //子数组A[q+1...r]

end

什么是dp;与分治的区别是什么?

动态规划是一种将复杂问题分解成很多子问题,并将子问题的求解结果存储起来避免重复求解的一种算法。

与分治的区别:动态规划法是将待求解问题分解成若干个相互重叠的子问题,而分治法是分解成若干个独立的子问题。

动态规划算法的基本要素:最优子结构;重叠子问题;状态转移方程

动态规划算法步骤:四步     

◼ 找出最优解的性质,并刻划其结构特征。

◼ 递归地定义最优值。

◼ 以自底向上的方式计算出最优值。

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

矩阵连乘; 最长公共子序列LCS; 最大字段和; 0-1背包

矩阵连乘:void MatrixChain(int n)

{

int r, i, j, k;

for (i = 0; i <= n; i++)//初始化对角线

{

m[i][i] = 0;

}

for (r = 2; r <= n; r++)//r个矩阵连乘

{

for (i = 1; i <= n - r + 1; i++)//r个矩阵的r-1个空隙中依次测试最优点

{

j = i + r - 1;

m[i][j] = m[i][i]+m[i + 1][j] + A[i - 1] * A[i] * A[j];

s[i][j] = i;

for (k = i + 1; k < j; k++)//变换分隔位置,逐一测试

{

int t = m[i][k] + m[k + 1][j] + A[i - 1] * A[k] * A[j];

if (t < m[i][j])//如果变换后的位置更优,则替换原来的分隔方法。

{

m[i][j] = t;

s[i][j] = k;

}

}

}

}

 

公共子序列:void LCS(int m,int n,char *x,char*y,int **c,int **b){

Int I,j;

For(i=1;i<=m;i++) c[i][0]=0;

For(j=1;j<=n;j++) c[0][j]=0;

For(i=1;i<=m;i++)

 For(j=1;j<=n;j++){

  If(x[i]==y[i])  C[i][j]=c[i-1][j-1]+1;b[i][j]=1;

  Else if(c[i-1][j]>=c[i][j-1])c[i][j]=c[i-1][j];b[i][j]=2;

  Else {c[i][j]=c[i][j-1];b[i][j]=3;}

}

}

最大子段和:n个数中选择一段区间[L,R](L<=R)使得这段区间对应的数字之和最大。

求解:动态规划,通过迭代更新子数组的和,同时记录最大值。

int maxsum(int n,int *a){

    dp[0]=0;

for(int i=1;i<=n;++i)

{

    dp[i]=max(dp[i-1]+a[i],a[i]);

  //i位置的情况可以分为:继承前面的所有数的总和+当前节点的和或仅选择当前节点

    Max=max(Max,dp[i]);

}

return Max;

}

 

01背包:略。求解 枚举法、回溯法:在枚举法的基础上进行约束剪枝和限界剪枝、动态规划

5.贪心策略

dp的特例:贪心算法

什么是贪心; 基本要素是什么;与dp的差异点是什么?

贪心选择性质:是指通过一系列局部最优选择,可以得到问题的整体最优解

最优子结构性质:一个问题的最优解包含其子问题的最优解 

贪心与dp的差异点:

动态规划每一步所做的选择都依赖于相关子问题的解(自底向上);贪心算法仅在当前状态做出最好的选择(局部最优选择,自顶向下)

经典问题求解: 活动安排; 最优装载; 哈夫曼编码;

最优装载:

Void load(int x[],Type w[],Type c,int n){

 Sort(w,n);

For(int i=1;i<=n;i++) x[i]=0;

For(int i=1;i<=n&&w[i],=c;i++){

X[i]=1;c-=w[i];}

}

哈夫曼编码:

哈夫曼提出构造最优前缀码的贪心算法,由此产生的编码方案称为哈夫曼编码

哈夫曼算法以自底向上的方式构造表示最优前缀码的二叉树T。

//伪代码

HUFFMAN(C)

n = |C|

Q = C

for  i = 1  to  n-1

allocate a new node z

z.left = x = EXTRACT-MIN(Q)

z.right = y = EXTRACT-MIN(Q)

z.freq = x.freq + y.freq

INSERT(Q,z)

return  EXRACT-MIN(Q)        //return the root of tree

 

6.回溯法与分支限界

回溯法:

是什么? 算法框架是什么? 递归回溯、迭代回溯两种框架是怎么表达的?

回溯法:以深度优先方式系统搜索问题解的算法。 

算法框架是什么?(1)递归回溯(2)迭代回溯

递归回溯、迭代回溯两种框架是怎么表达的?

递归回溯是对解空间作递归深搜

迭代回溯是对解空间作非递归深搜

子集树

For(int i=1i>=0;i--{//控制展开左右子树

     X[t]=I;           //X数组用来存放路径信息

     If(legal(t))

     Backtrack(t+1);//legal方法是判断生成这个节点是否满足

                      若满足则以此节点作为跟节点继续

第一次循环处理左子树,处理完之后,处理右子树

排列树

Else

For(int i=t;i<=n;i++)    排列树的选择

{

Swap(x[t],x[i]);            每个元素都可以当成一种选择 就是左右的交换

If(legal(t)) backtrack(t+1);

Swap(x[t],x[i]);            回到根节点的操作上下两层的交换

 

分支限界:

与回溯的异同

(1)求解目标:回溯法的求解目标是找出解空间树中满足约束条件的所有解,而分支限界法的求解目标则是找出满足约束条件的一个解,或是在满足约束条件的解中找出在某种意义下的最优解。

搜索方式的不同:回溯法以深搜解空间树,而分支限界法则以广搜或以最小耗费优先搜索解空间树。

(2) 都有最优子结构性质:一个问题的最优解包含其子问题的最优解 。都需要用限界约束函数减去不满足条件的分支,以提高效率。

算法框架:

(1)队列式(FIFO)分支限界法

按照队列先进先出(FIFO)原则选取下一个节点为当前扩展节点。

(2)优先队列式

按照优先队列中规定的优先级选取优先级最高的节点成为当前扩展节点。

如何提高算法效率:

1.解空间树的大小

2,活节点表的组织方式

3.限界函数的设计

4.分支策略的选择

posted @   流滢  阅读(18)  评论(0编辑  收藏  举报
(评论功能已被禁用)
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
点击右上角即可分享
微信分享提示