问题描述
N位同学站成一排,音乐老师要请其中的(N-K)位同学出列,使得剩下的K位同学排成合唱队形。
合唱队形是指这样的一种队形:设K位同学从左到右依次编号为1,2…,K,他们的身高分别为T1,T2,…,TK, 则他们的身高满足T1<…Ti+1>…>TK(1<=i<=K)。
你的任务是,已知所有N位同学的身高,计算最少需要几位同学出列,可以使得剩下的同学排成合唱队形。
思路
这道题其实想清楚了也就不难,就是求一个最长递增子序列的问题
(正用+反用)
这个的话,很明显就是要用动态规划来做,那么就又到了想dp数组含义的时候了,这里的话,我们要注意,dp数组的含义是:选择该点时,可得到的最长递增序列,还有一种思路是:到该点为止,可以得到的最长序列(该点可没说一定要选),这是一个挺大的坑,反正我之前在里头想当然了好久,不过这样的问题也好解决,最好的办法就是,自己拿笔跟着过程算一遍,基本就知道哪里有问题了
第二个坑呢,就是一定要看清楚题目要求的是什么,像这道题,它要的是最少需要出列几名同学,可千万不能想当然的觉得这是最长递增子序列就输出这个长度了,坑得很(好吧,是我自己不好好读题目,流下了悔恨的泪水)
最后一点呢,说不上是坑,算是一个知识点吧,就是关于memset的,这个函数呢,可以用来初始化数组,但是,可不要想当然的地猜测它的用法,也不多说,只要记住,只有想把数组初始化为-1或0时,他才管用,其他的值,啧啧啧,不可以用的!!!1都不行,具体原理可以去看memset的工作机制,它并不是为每个int赋值,自己看啦~
最长递增子序列
解释一下怎么求最长递增子序列吧,其实就是原序列的每一个元素自身都是一个递增子序列,长度为1(ps:这就是我们dp数组的初值,也可是说是出口状态),从第二位开始,选它时最长递增子序列是什么呢?其实就是找它前面的、比他小的(也就是说它可以加到那个序列后边的)最长序列+1,最长序列和最长递增子序列对应,+1和它加到该序列后形成一个新的最长对应
如果前面没有比它小的(他加不进去)怎么办?那就代表选它的话,最长递增只能是1了,也就是只有它本身,及初值,可不是前面的最大值不加1喔,这就关系到我最上面写的dp数组含义了
反向使用
其实因为这里要求的是一个山字形,我们要的可不是单纯的最长递增,而是最长递增和最长递减的结合最大,可以把最长递减当作一个反过程,不过其实一个意思,看个人喜好
最常公共子序列
这其实和这道题无关了,只是他们都是求序列,有都是用dp,我就想放一起写写
先来看子序列和子串的不同
对于abcdefg和acdegh这两个序列
cde是最长子串
acdeg是最长公共子序列
即:子串在原串中必须连续、子序列在原串中不一定连续
设 串A{a1,a2,a3…an}
串B{b1,b2,b3…bn}
其最长公共子序列为C{c1,c2,c3…ck}
若an=bn
则dp[an][bn]=dp[an-1][bn-1]+1
若an!=bn 同时 an=ck
则dp[an][bn]=dp[an][bn-1]
若an!=bn 同时 bn=ck
则dp[an][bn]=dp[an-1][bn]
搬运一下别人的图,就是这样
好了,就这样吧,hiahiahia,不想写了~
代码
#include <bits/stdc++.h>
using namespace std;
int main()
{
int n;
cin>>n;
int a[n];
int f[n];
int r[n];
for(int i=0;i<n;i++)
{
f[i]=r[i]=1;
}
for(int i=0;i<n;i++)
{
cin>>a[i];
}
int maxn;
for(int i=0;i<n;i++)
{
//maxn=1;
for(int j=0;j<i;j++)
{
if(a[j]<a[i])
{
f[i]=max(f[i],f[j]+1);
}
//else
//f[i]=max(maxn,f[j]);
}
}
for(int i=n-1;i>=0;i--)
{
//maxn=1;
for(int j=n-1;j>i;j--)
{
if(a[j]<a[i])
{
r[i]=max(r[i],r[j]+1);
}
//else
//r[i]=max(maxn,r[j]);
}
}/*
for(int i=0;i<n;i++)
{
cout<<f[i]<<" ";
}
cout<<endl;
for(int i=0;i<n;i++)
{
cout<<r[i]<<" ";
}
cout<<endl;*/
maxn=0;
for(int i=0;i<n;i++)
{
f[i]+=r[i];
//cout<<f[i]<<" ";
if(f[i]>maxn)
maxn=f[i];
}
//cout<<endl;
cout<<n-(maxn-1)<<endl;
return 0;
}