[PKU暑课笔记] 动态规划(二) 最长上升子序列 POJ1458最长公共子序列
来源:互联网 发布:wpf更新软件 编辑:程序博客网 时间:2024/05/22 12:07
五●例题
●最长上升子序列
1、子问题:求以ak(k=1, 2, 3…N)为终点的最长上升子序列的长度(一个上升子序列中最右边的那个数,称为该子序列的 “终点”)
2、确定状态:子问题只和一个变量--数字的位置相关。
因此序列中数的位置k就是“状态”,而状态 k 对应的“值”,就是以ak 做为“终点”的最长上升子序列的长度。
状态一共有N个。
3、状态转移方程:
maxLen (1) = 1【初始状态】
maxLen (k) = max { maxLen (i):1<=i < k 且 ai < ak且 k≠1 } + 1【若找不到这样的i,则maxLen(k) = 1】
maxLen(k)的值,就是在ak左边,“终点”数值小于ak ,且长度最大的那个上升子序列的长度再加1。
因为ak左边任何“终点”小于ak的子序列,加上ak后就能形成一个更长的上升子序列。
“人人为我”递推型动归程序
#include<iostream>#include<cstring>#include<algorithm>using namespace std;const int MAXN=1010;int a[MAXN];int maxlen[MAXN];int main(){ int n; cin>>n; for(int i=1; i<=n; ++i) { cin>>a[i]; maxlen[i]=1; } for(int i=2; i<=n; ++i) for(int j=1; j<i; ++j) { if(a[i]>a[j]) maxlen[i]=max(maxlen[i],maxlen[j]+1); } cout<<*max_element(maxlen+1,maxlen+n+1); return 0;}
“我为人人”递推型动归程序
/*#include<iostream>#include<cstring>#include<algorithm>using namespace std;const int MAXN=1010;int a[MAXN];int maxlen[MAXN];int main(){ int n; cin>>n; for(int i=1; i<=n; ++i) { cin>>a[i]; maxlen[i]=1; }*/ for(int i=1; i<=n; ++i) for(int j=i+1; j<=n; ++j)//看看能更新哪些状态的值 { if(a[j]>a[i]) maxlen[j]=max(maxlen[j],maxlen[i]+1); } /*cout<<*max_element(maxlen+1,maxlen+n+1); return 0;}*/
进一步,区分动规的3种形式
1)记忆递归型
优点:只经过有用的状态,没有浪费。递推型会查看一些没用的状态,有浪费
缺点:可能会因递归层数太深导致爆栈,函数调用带来额外时间开销。无法使用滚动数组节省空间。总体来说,比递推型慢。
==>人人为我==>我为人人
2)“人人为我”递推型:状态i的值Fi由若干个值已知的状态值Fk ,Fm ,..Fy推出,如求和,取最大值
在选取最优备选状态的值Fm,Fn,…Fy时,有可能有好的算法或数据结构可以用来显著降低时间复杂度。
3)“我为人人”递推型:状态i的值Fi在被更新(不一定是最终求出)的时候,
依据Fi去更新(不一定是最终求出)和状态i相关的其他一些状态的值Fk ,Fm ,..Fy
没有什么明显的优势,有时比较符合思考的习惯。个别特殊题目中会比“人人为我”型节省空间。
●一个补充:min_element()、max_element()和nth_element()
头文件:#include<algorithm>
作用:返回容器中最小值和最大值。max_element(first,end,cmp);//其中cmp为可选择参数???
#include<iostream> #include<algorithm> using namespace std; bool cmp(int a,int b) { return a<b; } int main() { int num[]={2,3,1,6,4,5}; cout<<"最小值是 "<<*min_element(num,num+6)<<endl; cout<<"最大值是 "<<*max_element(num,num+6)<<endl; cout<<"最小值是 "<<*min_element(num,num+6,cmp)<<endl; cout<<"最大值是 "<<*max_element(num,num+6,cmp)<<endl; return 0; }
●POJ1458 Common Subsequence 最长公共子序列 http://poj.org/problem?id=1458
输入两个串s1,s2,
设MaxLen(i,j):s1的左边i个字符形成的子串,与s2左边的j个字符形成的子串的最长公共子序列的长度(i,j从0开始算)
MaxLen(i,j) 就是本题的“状态”
假定 len1 = strlen(s1),len2 = strlen(s2),那么题目就是要求 MaxLen(len1,len2)
显然,
MaxLen(n,0) = 0 ( n=0…len1)
MaxLen(0,n) = 0 ( n=0…len2)
递推公式:
if ( s1[i-1] == s2[j-1] ) //s1的最左边字符是s1[0]
MaxLen(i,j) = MaxLen(i-1,j-1) + 1;
else
MaxLen(i,j) = Max(MaxLen(i,j-1),MaxLen(i-1,j) );
【时间复杂度O(mn)】
#include<iostream>#include<cstring>#include<algorithm>using namespace std;char s1[1000];char s2[1000];int maxlen[1000][1000];int main(){ while(cin>>s1>>s2) { int len1=strlen(s1); int len2=strlen(s2); int ntmp; for(int i=0;i<=len1;i++) maxlen[i][0]=0; for(int j=0;j<=len2;j++) maxlen[0][j]=0; for(int i=1;i<=len1;i++) for(int j=1;j<=len2;j++) { if(s1[i-1]==s2[j-1])// maxlen[i][j]=maxlen[i-1][j-1]+1; else maxlen[i][j]=max(maxlen[i][j-1],maxlen[i-1][j]); } cout<<maxlen[len1][len2]<<endl; } return 0;}
- [PKU暑课笔记] 动态规划(二) 最长上升子序列 POJ1458最长公共子序列
- 动态规划--(最长公共子序列 poj1458)
- POJ1458动态规划——最长公共子序列
- POJ1458最长公共子序列
- 最长公共子序列 poj1458
- 最长公共子序列 poj1458
- 最长公共子序列 poj1458
- poj1458最长公共子序列
- poj1458最长公共子序列
- POJ1458【最长公共子序列】
- POJ1458 最长公共子序列
- 最长公共子序列poj1458
- 动态规划(最长上升子序列)
- 最长上升子序列(动态规划)
- 最长上升子序列(动态规划)
- 最长上升子序列(动态规划)
- POJ1458(最长公共子序列)
- 最长公共子序列(poj1458)
- ZXing二维码编解码的使用
- 基于swagger phpunit打造全自动化php单元测试
- 怎么用html 显示出一横的多出来的文字,怎么实现CSS限制字数,超出部份显示点点点.
- vue-router动态利用配置内容
- linux一些常用命令
- [PKU暑课笔记] 动态规划(二) 最长上升子序列 POJ1458最长公共子序列
- <c:if test="value ne, eq, lt, gt,...."> 用法
- 水表识别
- Validate对select组件不进行验证的一种解决方法
- python字符串与非字符串拼接三种方式
- MyBatis,动态传入表名,字段名的解决办法转载()
- 微信小程序--wx:openLocation的坑
- 数据库的数据的不可读,脏读,幻读和丢失更新
- Linux命令分析: chmod