题目:
单调递增最长子序列
时间限制: 3000 ms | 内存限制: 65535 KB
难度: 4
代码1:
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <algorithm>
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
int main()
{
int n;
char str[10005];//存储字符串
int num[10005];//当前元素作为最大元素的最长递增序列
scanf("%d",&n);
while(n--)
{
mem(str,'\0');
mem(num,0);//初始化str和num
int sum=0;
num[0]=1;//第一个元素的最长递增序列一定为1
scanf("%s",str);
int len=strlen(str);
for(int i=1; i<len; i++)
{
int flag=0;//代表num[i]的值
for(int j=0; j<i; j++)
{
if(str[i]>str[j]&&flag<num[j])//把当前的第i个元素和前面的每一个元素比较&&递增序列必须连续递增
{
flag=num[j];//更新序列长度
}
}
num[i]=flag+1;
}
for(int i=0; i<len; i++)
{
sum=max(sum,num[i]);//找出里面最大的长度
}
printf("%d\n",sum);
}
return 0;
}
把上面的代码优化一下,可以用逆推的方式这么写
代码2:
#include<stdio.h>
#include<string.h>
int dp[10010];
char a[10010];
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
memset(dp,0,sizeof(dp));
int i,la,j,maxn=-1;
scanf("%s",a+1);
la=strlen(a+1);
for(i=1;i<=la;i++)
{
for(j=i-1;j>=0;j--)
{
if(a[j]<a[i]&&dp[i]<dp[j]+1)//判断是否递增,并且判断当前元素所处递增序列的长度
dp[i]=dp[j]+1;//更新递增序列的最大长度
}
if(dp[i]>maxn)
maxn=dp[i];
}
printf("%d\n",maxn);
}
return 0;
}
\
\
关于这个问题有一篇博客写的很好:--> 最长递增子序列详解(longest increasing subsequence)
以下内容摘自上述博客
-----------------------------------------------------------------关于单调递增子序列--------------------------------------------------------------------------------
对于动态规划问题,往往存在递推解决方法,这个问题也不例外。要求长度为i的序列的Ai{a1,a2,……,ai}最长递增子序列,需要先求出序列Ai-1{a1,a2,……,ai-1}中以各元素(a1,a2,……,ai-1)作为最大元素的最长递增序列,然后把所有这些递增序列与ai比较,如果某个长度为m序列的末尾元素aj(j<i)比ai要小,则将元素ai加入这个递增子序列,得到一个新的长度为m+1的新序列,否则其长度不变,将处理后的所有i个序列的长度进行比较,其中最长的序列就是所求的最长递增子序列。举例说明,对于序列A{35, 36, 39, 3, 15, 27, 6, 42}当处理到第六个元素(27)时,以35, 36, 39, 3, 15, 27, 6为最末元素的最长递增序列分别为
35
35,36
35,36,39
3
3,15
3,15,27
3,6
当新加入第10个元素42时,这些序列变为
35,42
35,36,42
35,36,39,42,
3,42
3,15,42
3,15,27,42
3,6,42\
这其中最长的递增序列为(35,36,39,42)和(3,15,27,42),所以序列A的最长递增子序列的长度为4,同时在A中长度为4的递增子序列不止一个。
该算法的思想十分简单,如果要得出Ai序列的最长递增子序列,就需要计算出Ai-1的所有元素作为最大元素的最长递增序列,依次
递推Ai-2,Ai-3,……,将此过程倒过来,即可得到递推算法,依次推出A1,A2,……,直到推出Ai为止
2018年3月31日20:06:37重写O(N^2)
#include <bits/stdc++.h>
using namespace std;
int dp[10000+100];
int main()
{
int t;
cin>>t;
while(t--)
{
int maxx=0;
string s;
cin>>s;
int len=s.length();
for(int i=0; i<len; i++)
{
dp[i]=1;
for(int j=0; j<i; j++)
{
if(s[j]<s[i]&&dp[j]+1>dp[i])
{
dp[i]=dp[j]+1;
}
}
maxx=max(maxx,dp[i]);
}
cout<<maxx<<endl;
}
return 0;
}
\