【算法设计与分析】(三)动态规划_更新中:斐波那契、二项式系数、树的最大独立集、最长递增、公共子序列、编辑距离、Hischberg、最优二叉搜索树、交替拿硬币、石子合并、背包、乘电梯

这篇具有很好参考价值的文章主要介绍了【算法设计与分析】(三)动态规划_更新中:斐波那契、二项式系数、树的最大独立集、最长递增、公共子序列、编辑距离、Hischberg、最优二叉搜索树、交替拿硬币、石子合并、背包、乘电梯。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

写在前面

分治
动态规划本篇 还差一堆
贪心
网络流

首先,怕误人子弟必须声明一下本人很菜(越复习越觉得完蛋了 作为一个科班研究生算法学成这样非常惭愧(跪 ,可能写的都不是很懂,很多内容打算背过去了。因为我发现好像真的有人看所以多提醒一句。。(大家就只食用目录吧

其次,本文只也许够应付考试,个人使用。而且其实就是ppt内容只是我自己喜欢这样整理。虽然全力理解内容且认真书写但也可能存在错误,如有发现麻烦指正,谢谢🌹

最后,因为不知道考试怎么考,本人的复习方式是照着目录讲一遍自己的理解+写伪代码(如果来的及会再做一个综合纯享版),再做一下上课讲过的例题和作业(印象里只有主定理、FFT、网络流上课练习+分治和动规两次作业)。

文章持续更新中,或许考前能发完也可能发不完。

祝我们好运🌹

动态规划

动机: 在递归求解的过程中重复求解子问题
策略空间换时间——将子问题保存下来避免重复计算
- 空间:子问题的数量(由子问题的参数决定)
关键:找到正确且高效的递归关系
求解:自顶向下/自底向上备忘录递归,自底向上没有递归调用的时空开销。

当难以建立递归关系考虑以下两种方案:

  • 增加约束条件
  • 增加参数

思路:

  • 建立一个新的表示
  • 基于这个新表示转化原问题
  • 考虑基本情况
  • 考虑归纳步骤

最重要的还是写归纳步骤的递归关系,想不出来那万事休矣。

斐波那契

1.递归

直接递归求解存在很多重复计算故考虑将历史记录保存
【算法设计与分析】(三)动态规划_更新中:斐波那契、二项式系数、树的最大独立集、最长递增、公共子序列、编辑距离、Hischberg、最优二叉搜索树、交替拿硬币、石子合并、背包、乘电梯,算法,动态规划

2.自顶向下动规(被动备忘录)

【算法设计与分析】(三)动态规划_更新中:斐波那契、二项式系数、树的最大独立集、最长递增、公共子序列、编辑距离、Hischberg、最优二叉搜索树、交替拿硬币、石子合并、背包、乘电梯,算法,动态规划

3.自底向上动规(主动备忘录)

从小到大计算
【算法设计与分析】(三)动态规划_更新中:斐波那契、二项式系数、树的最大独立集、最长递增、公共子序列、编辑距离、Hischberg、最优二叉搜索树、交替拿硬币、石子合并、背包、乘电梯,算法,动态规划

4.进一步优化(空间优化)

上一步的自底向上递归保存了所有的f(n),但实际上对于斐波那契当前需要求解的n的值来说只有n-1和n-2是有用的故只保存当前的数和前两个数,用三个变量即可。
【算法设计与分析】(三)动态规划_更新中:斐波那契、二项式系数、树的最大独立集、最长递增、公共子序列、编辑距离、Hischberg、最优二叉搜索树、交替拿硬币、石子合并、背包、乘电梯,算法,动态规划

二项式系数

1.递归

二项式系数是可以用C(N,K)直接求解的,但是大数计算容易溢出。
考虑数学的方式拆分组合数做递归
【算法设计与分析】(三)动态规划_更新中:斐波那契、二项式系数、树的最大独立集、最长递增、公共子序列、编辑距离、Hischberg、最优二叉搜索树、交替拿硬币、石子合并、背包、乘电梯,算法,动态规划
仍然是存在重复运算

2.自顶向下动规(被动备忘录)

都是一个套路的
【算法设计与分析】(三)动态规划_更新中:斐波那契、二项式系数、树的最大独立集、最长递增、公共子序列、编辑距离、Hischberg、最优二叉搜索树、交替拿硬币、石子合并、背包、乘电梯,算法,动态规划

3.自底向上动规(主动备忘录)

也是从小到大直接算,这里可以考虑不同的填写顺序
【算法设计与分析】(三)动态规划_更新中:斐波那契、二项式系数、树的最大独立集、最长递增、公共子序列、编辑距离、Hischberg、最优二叉搜索树、交替拿硬币、石子合并、背包、乘电梯,算法,动态规划

4.进一步优化(空间优化)

仍然是不需要过多的变量存储
【算法设计与分析】(三)动态规划_更新中:斐波那契、二项式系数、树的最大独立集、最长递增、公共子序列、编辑距离、Hischberg、最优二叉搜索树、交替拿硬币、石子合并、背包、乘电梯,算法,动态规划

树的最大独立集

1.问题定义

【算法设计与分析】(三)动态规划_更新中:斐波那契、二项式系数、树的最大独立集、最长递增、公共子序列、编辑距离、Hischberg、最优二叉搜索树、交替拿硬币、石子合并、背包、乘电梯,算法,动态规划

所谓树的独立集:两两不相邻顶点构成的集合。
而最大独立集:不被其他独立集包含即为最大。
问题就是给定一棵树返回最大独立集。

2.递归关系①

如何考虑这个问题:顶点在不在独立集里。
所以问题的解只有两种情况:
【算法设计与分析】(三)动态规划_更新中:斐波那契、二项式系数、树的最大独立集、最长递增、公共子序列、编辑距离、Hischberg、最优二叉搜索树、交替拿硬币、石子合并、背包、乘电梯,算法,动态规划
自底向上递归直接用树存储伪码:
【算法设计与分析】(三)动态规划_更新中:斐波那契、二项式系数、树的最大独立集、最长递增、公共子序列、编辑距离、Hischberg、最优二叉搜索树、交替拿硬币、石子合并、背包、乘电梯,算法,动态规划
这里面孩子用的递归调用孙子直接x.MIS暂且理解成x.MIS可以直接从备忘录读取
下面的也是一样的

3.递归关系②

仍然是考虑父节点在不在独立集里,只是换一种定义:
【算法设计与分析】(三)动态规划_更新中:斐波那契、二项式系数、树的最大独立集、最长递增、公共子序列、编辑距离、Hischberg、最优二叉搜索树、交替拿硬币、石子合并、背包、乘电梯,算法,动态规划

最长递增子序列-(作业)

子序列:序列顺序不变,可以不连续。
求解s[1 … n]的最长子序列

1.难以建立递归关系的两个解决方案

考虑递归求解一般的思路:知道了n-1的情况求n
假设知道了前n-1的最长递增子序列的长度,但是不知道n能不能放进去。
如果同时知道了n-1的长度和最后一个是几呢?知道n能不能放进去了。但是如果n不能放进去,也有可能存在另一个n-1序列能把n放进去。
但是又不可能把所有的序列记录。

当难以建立递归关系考虑以下两种方案

  • 增加约束条件:比如定义L(k)是以 k结尾/以k开头 的最长子序列的长度
  • 增加参数:定义L(i,j)中的 s(j…n)所有数都大于s[i]/小于s[i] 的最长子序列长度 *注意i和j是什么

2.增加约束自底向上动规

定义L(k)是以 k结尾 的最长子序列的长度
重新定义原问题:求解max L(k) (1<=k<=n)
考虑基本情况:k=1: L(k)=1
考虑递归关系:L(k) = max{1, max{L(i)+1}(i∈(1,k-1),如果s[k]>s[i]可以加上s[k],选最大的)} 记得跟1比。
【算法设计与分析】(三)动态规划_更新中:斐波那契、二项式系数、树的最大独立集、最长递增、公共子序列、编辑距离、Hischberg、最优二叉搜索树、交替拿硬币、石子合并、背包、乘电梯,算法,动态规划
时间复杂度: O ( n 2 ) O(n^2) O(n2)
一个例子:
【算法设计与分析】(三)动态规划_更新中:斐波那契、二项式系数、树的最大独立集、最长递增、公共子序列、编辑距离、Hischberg、最优二叉搜索树、交替拿硬币、石子合并、背包、乘电梯,算法,动态规划
反过来定义是一样的
【算法设计与分析】(三)动态规划_更新中:斐波那契、二项式系数、树的最大独立集、最长递增、公共子序列、编辑距离、Hischberg、最优二叉搜索树、交替拿硬币、石子合并、背包、乘电梯,算法,动态规划
关于作业问过的返回序列:
(简单贴一下我写的
思路:使用一个额外的数组来记录以每个位置结尾的最长递增子序列。当找到全局的最长递增子序列长度时,可以根据这个信息来重建最长递增子序列。具体见代码实现。

int lis_dp1(const vector<int>& s, int n) {
 // insert code here...
	// let the L(k) means the LIS's  last number is s[k]. the question is to get max(L(k))
	vector<int> L1(n);
	int answer = 1;
	for(int k=0;k<=n;k++){
        if(k==0){
            L1[k]=1;
        }
        else{
            for(int i=0;i<=k-1;i++){
                if(s[k]>s[i]){
                    L1[k] = max(L1[k],L1[i]+1);
                }
                L1[k] = max(1,L1[k]);
            }
        }
        answer = max(answer,L1[k]);
//        cout<<L1[k]<<endl;
    }
	return answer;
}
vector<int> find_lis_dp1(const vector<int>& s, int n) {
 // insert code here...
 	n++; 
 	vector<int> L1(n, 1);
    vector<int> prev_index(n, -1);

    int max_length = 1;
    int end_index = 0;

    for (int k = 1; k < n; k++) {
        for (int i = 0; i < k; i++) {
            if (s[k] > s[i] && L1[k] < L1[i] + 1) {
                L1[k] = L1[i] + 1;
                prev_index[k] = i;
            }
        }

        if (L1[k] > max_length) {
            max_length = L1[k];
            end_index = k;
        }
    }

    vector<int> result;
    while (end_index != -1) {
        result.insert(result.begin(), s[end_index]);
        end_index = prev_index[end_index];
    }

    return result;
}

3.增加子问题参数自底向上动规

定义L(i,j)中的 s(j…n)所有数都大于s[i] 的最长子序列长度
原问题转化:求L(0,1),s[0] = -∞
基本情况:j>n L(i,j)=0(二维数组边界)
递归关系:
【算法设计与分析】(三)动态规划_更新中:斐波那契、二项式系数、树的最大独立集、最长递增、公共子序列、编辑距离、Hischberg、最优二叉搜索树、交替拿硬币、石子合并、背包、乘电梯,算法,动态规划
时间空间复杂度都是 O ( n 2 ) O(n^2) O(n2)
定义成都小于s[i]也是一样的。
【算法设计与分析】(三)动态规划_更新中:斐波那契、二项式系数、树的最大独立集、最长递增、公共子序列、编辑距离、Hischberg、最优二叉搜索树、交替拿硬币、石子合并、背包、乘电梯,算法,动态规划

int lis_dp2(const vector<int>& s, int n) {
 // insert code here...
 	n++; //number 
 	vector<int> ss(n+1); //0-9 10
    for(int i=0;i<=n;i++){
        if(i==0) ss[i]=INT_MIN;
        else ss[i]=s[i-1]; 
    }
    int matrics_length = n+2; 
    vector<vector<int>> L2(matrics_length,vector<int>(matrics_length));
    for(int j=matrics_length-2;j>=0;j--){
        for(int i=matrics_length-2;i>=0;i--){
            if(j>n) L2[i][j]=0;
            else if(ss[i]>=ss[j]){
                L2[i][j]=L2[i][j+1];
            }
            else{
                L2[i][j]=max(L2[i][j+1],1+L2[j][j+1]);
            }
        }
    }
    return L2[0][1];
}
vector<int> find_lis_dp2(const vector<int>& s, int n) {
 // insert code here...
 	n++;
    vector<int> ss(n + 1);
    for (int i = 0; i <= n; i++) {
        if (i == 0) ss[i] = INT_MIN;
        else ss[i] = s[i - 1];
    }

    int matrics_length = n + 2;
    vector<vector<int>> L2(matrics_length, vector<int>(matrics_length));

    for (int j = matrics_length - 2; j >= 0; j--) {
        for (int i = matrics_length - 2; i >= 0; i--) {
            if (j > n) L2[i][j] = 0;
            else if (ss[i] >= ss[j]) {
                L2[i][j] = L2[i][j + 1];
            }
            else {
                L2[i][j] = max(L2[i][j + 1], 1 + L2[j][j + 1]);
            }
        }
    }

    int length = L2[0][1];
    vector<int> result;
    int i = 0, j = 1;

    while (j < matrics_length - 1) {
        if (ss[i] < ss[j] && L2[i][j] == 1 + L2[j][j + 1]) {
            result.push_back(ss[j]);
            i = j;
        }
        j++;
    }

    return result;
}
  • 贴一下反过来的:
  • 【算法设计与分析】(三)动态规划_更新中:斐波那契、二项式系数、树的最大独立集、最长递增、公共子序列、编辑距离、Hischberg、最优二叉搜索树、交替拿硬币、石子合并、背包、乘电梯,算法,动态规划

4.对第一种思路进一步加约束优化

  • key:对于长度为k的最长递增子序列,只需要记住末尾元素最小的
  • 【算法设计与分析】(三)动态规划_更新中:斐波那契、二项式系数、树的最大独立集、最长递增、公共子序列、编辑距离、Hischberg、最优二叉搜索树、交替拿硬币、石子合并、背包、乘电梯,算法,动态规划
    时间复杂度:O(logn)
int lis_dp3(const vector<int>& s, int n) {
 // insert code here...
	vector<int> last(1);
    last[0]=INT_MIN;
    for(int k=0;k<=n;k++){
        if(k==0){
            last.insert(last.end(),s[k]);
        }
        else{
            int last_id = last.size()-1;
            if(s[k]>last[last_id]){
                last.insert(last.end(),s[k]);
            }
            else{
                for(int i=last_id;i>=0;i--){
                    if(s[k]>last[i]){
                        last[i+1]=s[k];
                        break;
                    }
                }
            }
            
        }
//         cout<<"k="<<k<<"  s[k]="<<s[k]<<"  last:"<<last<<endl;
    }		

    return last.size()-1;
	
}

【算法设计与分析】(三)动态规划_更新中:斐波那契、二项式系数、树的最大独立集、最长递增、公共子序列、编辑距离、Hischberg、最优二叉搜索树、交替拿硬币、石子合并、背包、乘电梯,算法,动态规划

编辑距离

1.问题定义

需要编辑的个数和为编辑距离,目标是让一个字符串转成另外一个让编辑距离最小。
提出序列比对:可视化修改字符串的过程。上行为原字符串,下行为需要更改的。第一行的空格表示插入第二行空格表示删除。上下不同的个数和就是编辑距离。

3. 递归关系

思路:考虑最后一列。
我觉得其实这个二位数组可以这样理解:填写顺序从左上到右下,每填写一个格子,这个格子所在的行和列就全都填写完。向右和向下是插入或者删除,而向右下就是在替换
【算法设计与分析】(三)动态规划_更新中:斐波那契、二项式系数、树的最大独立集、最长递增、公共子序列、编辑距离、Hischberg、最优二叉搜索树、交替拿硬币、石子合并、背包、乘电梯,算法,动态规划

2. 例子

【算法设计与分析】(三)动态规划_更新中:斐波那契、二项式系数、树的最大独立集、最长递增、公共子序列、编辑距离、Hischberg、最优二叉搜索树、交替拿硬币、石子合并、背包、乘电梯,算法,动态规划
上面图对应的三条路
【算法设计与分析】(三)动态规划_更新中:斐波那契、二项式系数、树的最大独立集、最长递增、公共子序列、编辑距离、Hischberg、最优二叉搜索树、交替拿硬币、石子合并、背包、乘电梯,算法,动态规划

Hischberg’s algorithm

上面的改进:用O(m+n)空间构造最优比对
直觉上是创建一个编辑图,求左上到右下的最短路径
我觉得不会考QAQ

最长公共子序列

最优二叉搜索树

交替拿硬币

石子合并

背包

每个物品存在价值v和重量w,给定背包最大承重W求如何放让价值最大。

递归关系

思路:考虑已知前n-1个物品的最优解,最后一个能不能放,能放的话放或不放取最优。
基本情况:n=0 那价值为零
【算法设计与分析】(三)动态规划_更新中:斐波那契、二项式系数、树的最大独立集、最长递增、公共子序列、编辑距离、Hischberg、最优二叉搜索树、交替拿硬币、石子合并、背包、乘电梯,算法,动态规划

乘坐电梯

1.问题描述

n个人,给出体重w[n]
电梯承重x
问最少几趟电梯能把人送下去

2.思路

考虑知道了n-1个人的最优解,最后一个人考虑能不能装进任何一趟,不能就新开一个。
问题在于这个最后一个人的选择,这是一个运送顺序的问题。
把假设扩大:

  • 假设对{1 … n}的任意子集c,可以计算他的最优运送B( c )
  • 这个B( c )需要记录两个值:B( c ).first运送趟数,

吃个饭先文章来源地址https://www.toymoban.com/news/detail-805007.html

3.例子

到了这里,关于【算法设计与分析】(三)动态规划_更新中:斐波那契、二项式系数、树的最大独立集、最长递增、公共子序列、编辑距离、Hischberg、最优二叉搜索树、交替拿硬币、石子合并、背包、乘电梯的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包赞助服务器费用

相关文章

  • 【算法优选】 动态规划之斐波那契数列模型

    动态规划相关题目都可以参考以下五个步骤进行解答: 状态表⽰ 状态转移⽅程 初始化 填表顺序 返回值 后面题的解答思路也将按照这五个步骤进行讲解。 泰波那契序列 Tn 定义如下: T0 = 0, T1 = 1, T2 = 1, 且在 n = 0 的条件下 Tn+3 = Tn + Tn+1 + Tn+2 给你整数 n,请返回第 n 个泰波那契

    2024年02月05日
    浏览(14)
  • Java数据结构与算法:动态规划之斐波那契数列

    大家好,我是免费搭建查券返利机器人赚佣金就用微赚淘客系统3.0的小编。在这寒冷的季节里,让我们一同探讨Java中的动态规划,重点关注解决问题的经典代表之一——斐波那契数列。 动态规划简介 动态规划是一种解决问题的数学方法,通常用于优化递归算法。它通过将问

    2024年01月22日
    浏览(11)
  • 算法刷题Day 38 动态规划理论基础+斐波那契数+爬楼梯

    动态规划的解题步骤: 确定 dp 数组(dp table)以及下标的含义 确定递推公式 dp 数组如何初始化 确定遍历顺序 举例推导 dp 数组 很基础

    2024年02月15日
    浏览(29)
  • 数据结构与算法之动态规划: Leetcode 509. 斐波那契数 (Typescript版)

    斐波那契数 https://leetcode.cn/problems/fibonacci-number/ 描述 斐波那契数 (通常用 F(n) 表示)形成的序列称为 斐波那契数列 。该数列由 0 和 1 开始,后面的每一项数字都是前面两项数字的和。也就是: 给定 n ,请计算 F(n) 。 示例 1 示例 2 示例 3 提示 0 = n = 30 算法实现 1 )方案 1 这

    2024年02月04日
    浏览(10)
  • 算法Day38 | 动态规划,509. 斐波那契数, 70. 爬楼梯, 746. 使用最小花费爬楼梯

    动态规划是一种解决问题的算法思想。它通常用于优化问题,其中要求找到一个最优解或最大化(最小化)某个目标函数。 动态规划的核心思想是 将问题分解成更小的子问题,并通过存储子问题的解来避免重复计算 。这样,可以通过解决子问题来构建原始问题的解。动态规

    2024年02月09日
    浏览(6)
  • [算法分析与设计] 2. 斐波那契堆及其应用

    一个优先队列需要支持的操作有 insert 插入元素 (x) 。 find-min 返回最小的元素。 delete-min 删除最小的元素。 decrease-key 将一个元素 (x) 减小 (k) 。 (k geq 0) 。 常用于实现优先队列的数据结构是 堆 。 需要注意的是,小根堆需要支持 decrease-key,大根堆需要支持 increase-key。对

    2024年02月08日
    浏览(6)
  • 动态规划-斐波那契数

    斐波那契数是一个很好的熟悉和理解动态规划的例子,通过斐波那契数可以更好的理解动态规划的精髓,动态规划是后面的计算是如何借助于前面的计算结果来加快计算速度的。 斐波那契数和斐波那契数列其实可以看成是一道题,只不过两题的限制性条件稍微有差别 斐波那

    2024年02月14日
    浏览(8)
  • 【动态规划】是泰波那契数,不是斐波那契数

    【动态规划】是泰波那契数,不是斐波那契数

    Problem: 1137. 第 N 个泰波那契数 首先我们来解读一下本题的意思🔍 相信读者在看到【泰波那契数】的时候,不禁会联想到【斐波那契数】,它们呢是一对孪生兄弟,这个 泰波那契数 相当于是 斐波那契数 的加强版 我们首先可以来看到这个递推公式 Tn+3 = Tn + Tn+1 + Tn+2 ,读者可

    2024年02月08日
    浏览(10)
  • 【动态规划】斐波那契数列模型

    【动态规划】斐波那契数列模型

    冻龟算法系列之斐波那契数列模型 动态规划(英语:Dynamic programming,简称 DP) ,是一种在数学、管理科学、计算机科学、经济学和生物信息学中使用的,通过把原问题分解为相对简单的子问题的方式求解复杂问题的方法。动态规划常常适用于有重叠子问题和最优子结构性质

    2024年02月09日
    浏览(9)
  • 算法训练第三十八天|动态规划理论基础、509. 斐波那契数 、70. 爬楼梯 、 746. 使用最小花费爬楼梯

    算法训练第三十八天|动态规划理论基础、509. 斐波那契数 、70. 爬楼梯 、 746. 使用最小花费爬楼梯

    参考:https://programmercarl.com/%E5%8A%A8%E6%80%81%E8%A7%84%E5%88%92%E7%90%86%E8%AE%BA%E5%9F%BA%E7%A1%80.html 动态规划是什么 动态规划,英文:Dynamic Programming,简称DP,如果某一问题有很多重叠子问题,使用动态规划是最有效的。 所以 动态规划中每一个状态一定是由上一个状态推导出来的 ,这一

    2024年02月04日
    浏览(12)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包