赞
踩
1.最长上升子序列(LIS问题) 大佬博客: 最长上升子序列题目大合集
问题描述:给定一个长度n的数列A,求单调递增的子序列的长度最长是多少。
经典基础题:1759:最长上升子序列
描述 一个数的序列bi,当b1 < b2 < ... < bS的时候,我们称这个序列是上升的。对于给定的一个序列(a1, a2, ..., aN),我们可以得到一些上升的子序列(ai1, ai2, ..., aiK),这里1 <= i1 < i2 < ... < iK <= N。比如,对于序列(1, 7, 3, 5, 9, 4, 8),有它的一些上升子序列,如(1, 7), (3, 4, 8)等等。这些子序列中最长的长度是4,比如子序列(1, 3, 5, 8).
你的任务,就是对于给定的序列,求出最长上升子序列的长度。 输入 输入的第一行是序列的长度N (1 <= N <= 1000)。第二行给出序列中的N个整数,这些整数的取值范围都在0到10000。 输出 最长上升子序列的长度。 样例输入
- 7
- 1 7 3 5 9 4 8
样例输出
4
a[ i ]表示第i个数,而h[ i ]表示到第i个数时,它是第几个从第“零”个数延伸到的,相当于如下表格
思路:每访问输入的一个数a[i],求往前面找比起小的一个数a[j],则h[i]=h[j]+1.状态转移方程:h[i]=max{h[j]+1},j<i
代码:
- #include<bits/stdc++.h>
- using namespace std;
- int a[108],h[108];
- int main()
- {
- int n;
- scanf("%d",&n);
- for(int i=1;i<=n;i++)
- {
- scanf("%d",&a[i]);
- h[i]=1;
- for(int j=n-1;j>=1;j--)///向前寻找比a[i]小的数
- {
- if(a[j]<a[i])
- {
- h[i]=max(h[i],h[j]+1);
- }
- }
- }
- int maxx=*max_element(h+1,h+1+n);///求数组里的最大值,最小值同理
- printf("%d\n",maxx);
- return 0;
- }
2.最长公共子序列(LCS)
问题描述:给定两个长度分别为N和M的字符串A和B,求既是A的子序列又是B的子序列的字符串长度最长是多少。
转移方程: if(A[i]==B[j])
边界:f[i,0]=f[0,j]=0 目标:f【N,M】 状态表示:f[i,j]表示前缀子串A【1~i】与B【1~j】的最大公共子序列
经典例题:
例题1:最长公共子序列(POJ1458)大佬博客:动态规划典型例题详解(最长公共子序列(POJ1458), Help Jimmy(POJ1661))
给出两个字符串,求出这样的一 个最长的公共子序列的长度:子序列 中的每个字符都能在两个原串中找到, 而且每个字符的先后顺序和原串中的 先后顺序一致。
输入
abcfbc abfcab
programming contest
abcd mnp
输出
4
2
0
大佬思路:
解题思路:
遇见动归问题,第一步需要考虑状态是什么。
输入两个串s1,s2
设MaxLen(i,j)表示:s1的左边i个字符形成的子串,与s2左边的j个 字符形成的子串的最长公共子序列的长度(i,j从0 开始算),则MaxLen(i,j) 就是本题的“状态”
第二步,就是动用小脑子了,考虑下可能的情况还有递推公式。
对这道题来说
MaxLen(n,0) = 0(这里的n是属于s1的)
MaxLen(0,n) = 0(这里的n是属于s2的)
递推公式:
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));
注:s1[i - 1] != s2[j - 1]时,MaxLen(s1,s2)不会比MaxLen(s1,s2j - 1)和MaxLen(s1i - 1,s2)两者之中任何一个小,也不会比两者都大。
分析:动态规划现在的状态是由前一个状态通过max或min比较得来,由状态表示方程可知 通过枚举一个A【1~i】的元素与另一个串里B【1~j】里的元素比较相同就+,不同就选取最大的
代码:
- #include<bits/stdc++.h>
- using namespace std;
- int maxx[108][108];
- int main()
- {
- string s1,s2;
- while(cin>>s1>>s2)
- {
- int length1=s1.length();
- int length2=s2.length();
- for(int i = 0 ; i <= length1 ; i++)
- maxx[i][0] = 0;
- for(int j = 0 ; j <= length2 ; j++)
- maxx[0][j] = 0;
- for(int i=1;i<=length1;i++)
- {
- for(int j=1;j<=length2;j++)
- {
- if(s1[i-1]==s2[j-1])
- {
- maxx[i][j]=maxx[i-1][j-1]+1;
- }
- else
- maxx[i][j]=max(maxx[i][j-1],maxx[i-1][j]);
- }
- }
- printf("%d\n",maxx[length1][length2]);
- }
- return 0;
- }
3.数字三角形
问题描述:给定一个共有n行的三角形矩阵A,其中第i行有i列。从左上角出发,每次可以向下方或者右下方走一步,最终到达底部。求把经过的所有位置的和加起来,和最大是多少。
状态表示:f【i】【j】表示从左上角走到第i行第j列,和最大是多少。
阶段划分:路径的结尾位置(矩阵中的行,列位置,即一个二维坐标)
边界:f[1,1]==A[1,1] 目标:max{f[N,j]}
通过一道例题理解:
描述
如下所示的由正整数数字构成的三角形:
7
3 8
8 1 0
2 7 4 4
4 5 2 6 5
从三角形的顶部到底部有很多条不同的路径。对于每条路径,把路径上面的数加起来可以得到一个和,和最大的路径称为最佳路径。你的任务就是求出最佳路径上的数字之和。
注意:路径上的每一步只能从一个数走到下一层上和它最近的下边(正下方)的数或者右边(右下方)的数。
输入
第一行为三角形高度100>=h>=1,同时也是最底层边的数字的数目。
从第二行开始,每行为三角形相应行的数字,中间用空格分隔。
输出
最佳路径的长度数值。
样例输入
- 5
- 7
- 3 8
- 8 1 0
- 2 7 4 4
- 4 5 2 6 5
- 或
- 1
- 8
样例输出
- 30
- 或
- 8
分析:后一个状态由前面一个状态所确定,令f【】
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。