【基础算法】最长上升子序列
时间限制: 1 Sec 内存限制: 64 MB题目描述
给定一个整数序列A1A2A3….An。求它的一个递增子序列,使子序列的元素个数尽量多,元素不一定要求连续。
输入
第1行:1个整数n(1<=n<=5000),表示序列中元素的个数.
第2行-n+1行:每行1个整数x(-1000<=x<=1000),第i+1行表示序列中的第i个元素。
输出
第1行:1个整数k,表示最长上升子序列的长度。
第2行:k个用单个空格分开的整数,表示找到了最长上升子序列。如果有多个长度等于k的子序列,则输出最靠前的1个。
样例输入
8
1
3
2
4
3
5
4
6
样例输出
5
1 3 4 5 6
#--------------------------------------------------------------------------------#
最基础的动规题~就让我来详细地为小白们讲解一下吧
首先,讲解一下题目:
给你一个序列(就一串数),你可以理解为几个人。
这几个人身高各不相同(有的很矮(两三厘米什么的不要在意),有的很高(也就一两千厘米))。
现在你要在这几个人当中找出一些人做苦力怕,你需要使揪出来的人的身高从低到高(不改变顺序的情况下)排列。
当然,我们都希望人越多越好~就是让你算出最多有多少,并输出他们的编号。
再解释一下样例:
八个数:1 3 2 4 3 5 4 6
这几个人的身高……呵呵,要抓出几个来,使身高为从低到高排列,例如:
1 4 5 6
我们抓的就是①、④、⑥和⑧号犯人,这样就是从低到高了。
但是,这样是不是最多的呢,显然不是,最多的是:
1 3 4 5 6
就抓了①、②、④、⑥和⑧号犯人,他们就很荣幸地成为了苦力。
这里有一个细节——升高一样是不能在一起的,你可以理解为两个身高一样的在一起,我说我高,你说你高,于是便打起架来了……
当然,这只是针对于“最大上升子序列”,其他的也是一样,只是排列方式不同而已,如“最大不上升子序列”,就是抓出一堆人,使身高从高到低排列(可以一样(大概是他们不敢打架吧,不要在意细节))。
#--------------------------------------------------------------------------------#
好的题目解释完了,怎么做呢?
啊啊哈哈哈,当然是直接选就行了啊,专业名词——贪心
好的,很不幸,用贪心是不行的……
这里就要用一种新东西——动态规划(简称动规)
这种东西到底是什么呢,
总之,这是一种递推的思想,你需要将当前的状态(原谅我我找不出更好的词)用之前的状态表示出来,最后只需一个循环,你就可以通过f[1]得到f[n](通常是指最优解问题)。
好的,对于这道题,我们可以列出一个方程(且称这猥琐的东西为方程):
f[i]=max{f[1],f[2],...,f[i-1]}+1
总之,这是一种递推的思想,你需要将当前的状态(原谅我我找不出更好的词)用之前的状态表示出来,最后只需一个循环,你就可以通过f[1]得到f[n](通常是指最优解问题)。
好的,对于这道题,我们可以列出一个方程(且称这猥琐的东西为方程):
f[i]=max{f[1],f[2],...,f[i-1]}+1
这是什么意思呢?首先:
f[i]表示的就是第i个人(必须要有第i个人)之前最多可以抓多少个苦力,显然,f[1]=1,因为第1个人之前没有人比TA高……
max应该不陌生,就是取f[1],f[2],...,f[i-1]中最大的。
但是,如果你明白了一些,肯定会问:第i个人不一定比1-(i-1)人都要高啊?
所以,还是让j从1到i-1开始枚举f[j],但是,在选最大的时候要再加一个条件:a[j]
为什么最后还要加1呢?看看前面:“f[i]表示的就是第i个人(必须要有第i个人)”,所以,算上i,还要再加1。
关于求最多苦力就是这样了。
接下来还有,要输出苦力的编号:
在找maxi的时候,就把j记录下来,最后递归输出,这部分详情看代码。
有问题欢迎留言~
代码:
#include
#include
int a[5005],n,maxans,flag=1;//a为原始数组,n是人数量,maxans表示最多的苦力在f中的哪个位置
int f[5005],ans[5005];//f是动规数组,ans是存最多苦力的编号的数组
void print(int x)
{
if(ans[x]!=0)//直到父亲为0(没有了)
print(ans[x]);
if(flag) printf("%d",a[x]),flag=0;
else printf(" %d",a[x]);//flag控制多余空格
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);//读入
for(int i=1;i<=n;i++)
{
int maxi=0;//寻找f[1],f[2],...,f[i-1]中最大且符合条件的一个
for(int j=1;jmaxi&&a[j]f[maxans])//找最大的
maxans=i;
}
printf("%d\n",f[maxans]);
print(maxans);
}
By WZY