算法第三章作业
一、题目:3-1 调递增最长子序列
1.1、递归方程式
a= max{maxnum,b[i]} (0 <= j < i || a[i] > a[j]) ; 其中maxnum表示到当前位置的前一个位置的最大值,b[i]表示到当前的最大值。
1.2、表的维度:一维表 范围:0-n 顺序:自左向右
1.3、时间复杂度:O(n^2) 空间复杂度:O(n)
2.实现代码
#include<bits/stdc++.h> using namespace std; #define num 100 int a[1001]; int LMax(int n){ int b[num]={0}; b[1]=1;//数组只有一个数时,最长为1 int max=0; for(int i=2;i<=n;i++){ int k=0; for(int j=1;j<i;j++){ if(a[j]<=a[i]&&k<b[j]){ k=b[j]; b[i]=k+1; } if(max<b[i]){ max=b[i]; } } } return max; } int main(){ int n; cin>>n; for(int i=1;i<=n;i++){ cin>>a[i]; } cout<<LMax(n)<<endl; }
原先我想不通过动态规划完成,虽然本地跑样例过了,但是pta测试点1老是过不了,后来经过测试,发现这种方法对于1 97 98 99 2 4 6 3 5 7这种样例,输出的却是4,也就是说,对于中间隔较多比后面大的数字,会由于两指针的往后跳动导致后面即使比较于最前面是递增的数字无法比较到,所以还是需要用到动态规划,用备忘录记录。
代码如下
#include<iostream> using namespace std; int Longest(int n, int a[]){ int b[1001]; int max=0, t, k; b[0] = 1; for(int i=1;i<n;i++){ for(t=0,k=0;k<i;k++){ if(a[k]<=a[i] && t<b[k]) t = b[k]; } b[i] = t+1; if(b[i]>max) max = b[i]; } return max; } int main(){ int n; int a[1001]; cin >> n; for(int i=0;i<n;i++){ cin >> a[i]; } cout << Longest(n, a) << endl; return 0; }
二、对动态规划算法的理解
动态规划是一个比较难的算法,理解起来很抽象,下面谈谈我的理解。
递归到动规的一般转化方法
递归函数有n个参数,就定义一个n维的数组,数组的下标是递归函数参数的取值范围,数组元素的值是递归函数的返回值,这样就可以从边界值开始, 逐步填充数组,相当于计算递归函数值的逆过程。
解题思路
1. 将原问题分解为子问题
把原问题分解为若干个子问题
2.确定状态
在用动态规划解题时,我们往往将和子问题相关的各个变量的一组取值,称之为一个“状 态”。一个“状态”对应于一个或多个子问题, 所谓某个“状态”下的“值”,就是这个“状 态”所对应的子问题的解。
3.确定一些边界的值
4.确定递归表达式
能用动规解决的问题的特点
1) 问题具有最优子结构性质。如果问题的最优解所包含的 子问题的解也是最优的,我们就称该问题具有最优子结 构性质。
2) 无后效性。当前的若干个状态值一旦确定,则此后过程的演变就只和这若干个状态的值有关,和之前是采取哪种手段或经过哪条路径演变到当前的这若干个状态,没有关系。
三.结对编程情况:
这次两人用两种方法解出,导致交流少了些,虽然用了递归,但是没考虑到效率问题,没有备忘录记录前面已解的那些结果,会大大加大时间浪费。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步