单调递增最长子序列
时间限制:
3000 ms | 内存限制:
65535 KB
难度:
4
-
描述
-
求一个字符串的最长递增子序列的长度
如:dabdbf最长递增子序列就是abdf,长度为4-
输入
-
第一行一个整数0<n<20,表示有n个字符串要处理
随后的n行,每行有一个字符串,该字符串的长度不会超过10000
输出
- 输出字符串的最长递增子序列的长度 样例输入
-
3 aaa ababc abklmncdefg
样例输出
-
1 3 7
-
解题思路
-
先解释下什么叫子序列。若a序列删去其中若干个元素后与b序列完全相同,则称b是a的子序列。
-
我们假定存在一个单调序列{An}(以递增序列为例),现在在其后面添加一个元素a(n+1), 有两种情况: 1.a(n+1)>a(n)。 此时,a(n+1)可以添加到An序列的尾部,形成一个新的单调序列, 并且此序列长度大于之前An的长度; 2.a(n+1)<=a(n)。此时,a(n+1)当然不可以添加到An序列的尾部。 经过分析,我们可以得出这样的结论: 一个单调序列与其后面元素的关系仅与此序列的末尾元素有关。 如此,便有了此题如下的dp解法: 建立一个一维数组dp[ ],用dp[i]保存长度为i的单调子序列的末尾元素的值, 用top保存单调子序列的最大长度。 初始top=1,dp[1]=a1; 然后,我们从前向后遍历序列An(i : 2~n)。显然,我们会遇到两种情况: 1.a[i] > dp[top]。 此时,我们把a[i]加入到长度为top的单调序列中,这时序列长度为top+1, top值也跟着更新,即dp[++top] = a[i]; 2.a[i]<=dp[top]。 此时,a[i]不能加入长度为top的单调序列,那它应该加入长度为多少的序列呢? 做法是,从前向后遍历dp[ ] (j: 1~top-1),直到满足条件 a[i] > dp[j], 此时,我们将dp[j]的值更新为a[i]。 可是,为什么要更新它呢? 因为对于相同长度的单调递增序列来说,末尾元素的值越小, 其后元素加入此序列的可能性越大,也就是说,我们这样做,是为了防止丢失最优解。
-
例:
-
s abclmndefg dp abclmn abcdmn abcden ... abcdefg
-
代码
-
#include<stdio.h> #include<string.h> char s[11000],dp[11000]; int main() { int n; int len; int i,j,k; int max; scanf("%d",&n); while(n--) { scanf("%s",s); len=strlen(s); memset(dp,0,sizeof(dp)); dp[1]=s[0]; max=1; for(i=1;i<len;i++) { if(s[i]>dp[max]) dp[++max]=s[i]; else { for(j=1;s[i]>dp[j];j++) { } dp[j]=s[i]; } } printf("%d\n",max); } return 0; }
-
第一行一个整数0<n<20,表示有n个字符串要处理