1. 任选作业题”单调递增最长子序列“、”挖地雷“、”编辑距离问题“中的一题分析。
我选“单调递增最长子序列”做分析。
问题如下
设计一个O(n2)时间的算法,找出由n个数组成的序列的最长单调递增子序列。
输入格式:
输入有两行: 第一行:n,代表要输入的数列的个数 第二行:n个数,数字之间用空格格开
输出格式:
最长单调递增子序列的长度
输入样例:
在这里给出一组输入。例如:
5
1 3 5 2 9
输出样例:
在这里给出相应的输出。例如:
4
#include<iostream> using namespace std; int DL(int a[], int b[],int n) { for (int i = 1; i < n; i++) { for (int j = 0; j < i; j++) { if (a[j] < a[i]&& b[j]>b[i] - 1) { b[i] = b[j] + 1; } } } int t = b[1]; for (int k = 0; k < n; k++) { if (b[k] > t) { t = b[k]; } } return t; } int main() { int n; cin >> n; int *a = new int[n]; int *b = new int[n]();//置为0; for (int i = 0; i < n; i++) { b[i]++; } for (int i = 0; i < n; i++) { cin >> a[i]; } cout << DL(a, b, n); return 0; }
1.1 根据最优子结构性质,列出递归方程式,
b[i]= b[j] +1 (0<j<i,a[i]>a[j]
1.2 给出填表法中表的维度、填表范围和填表顺序。
维度:一维表b[];
填表范围:b[0]~b[n]
填表顺序:从左到右
1.3 分析该算法的时间和空间复杂度
时间复杂度:O(n^2)
空间复杂度:S(n)
2. 你对动态规划算法的理解
(1)基本思想:
动态规划算法的基本思想与分治法类似:将待求解的问题分解成若干个子问题,先求解子问题,然后从这些子问题的解中得到原问题的解。但是,与分治法不同的是,为了避免重复多次计算子问题,动态规划算法用一个表记录所有已解决的子问题的答案,不管该子问题以后是否被利用,只要它被计算过,就将其结果填入表中。
(2)设计动态规划算法的步骤:
①找出最优解的性质,并刻画其结构特征
②递归地定义最优值
③以自底向上的方式计算最优值
④根据计算最优值时得到的信息构造最优解
(3)动态规划算法的基本要素
①最优子结构性质
当问题的最优解包含了子问题的最优解时,称该问题具有最优子问题结构。在动态规划算法中,利用问题的最优子结构性质,以自底向上的方式递归地从子问题的最优解逐步构造出整个问题的最优解。
②重叠子问题性质
在用递归算法自顶向下解决问题时,每次产生的子问题并不总是新问题,有些子问题可能被反复计算多次。动态规划算法利用这种子问题的重叠性质,对每一个子问题只解一次,而后将其解保存在一个表格中,当再次需要解此子问题时,只需要简单地用常数时间查看一下结果即可。
从一般意义上讲,问题所具有的最优子结构性质和重叠子问题性质是该问题可用动态规划算法求解的基本要素。
③备忘录方法
备忘录方法是动态规划算法的变形。与动态规划算法一样,备忘录方法用表格保存已解决的子问题的答案,在下次解决问题时,只要简单地查看该子问题的解答,不必再次计算。与动态规划算法不同的是,备忘录方法的递归方式是自顶向下的,而动态规划算法则是自底向上的。
备忘录方法为每个子问题建立一个记录项,初始化时,该记录项存入一个特殊的值,表示该子问题尚未求解。在求解的过程中对每个待求解的子问题,首先查看相应的记录项。若记录项存储的是初始化的特殊值,则需要计算该子问题的解,并保存在相应的记录项中已备以后查看。若记录项存储的不是初始值,则表示该子问题已被计算过,此时记录项存储的值即该子问题的解答。
3. 说明结对编程情况
结对编程过程中与搭档发现了很多自己没有注意到的问题,感到自己需要更加努力!