最长上升子序列题目大合集
先看看第一题,再由点到面地延伸:
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个数时,它是第几个从第“零”个数延伸到的,相当于如下表格:
程序实现相当于,每访问一个数i,就往前找,直到找到一个比其小的数j,那么h[ i ] = h[ j ]+1
最后找出整个h里最大的就行了
插一句,找一个一维数组里最大的可以使用:s = *max_element(a+1,a+n+1)来实现,要使用头文件algorithm,最小则把max改成min
代码实现:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int a[5001][2];
int main()
{
int i=1,j,n;
int ss=0;
scanf("%d",&n);
for(i=1;i<=n;i++)
{
scanf("%d",&a[i][0]);
a[i][1]=1;
for(j=i-1;j>0;j--)
if(a[j][0]<a[i][0])
a[i][1]=max(a[j][1]+1,a[i][1]);
}
for(i=1;i<=n;i++)
ss=max(ss,a[i][1]);
printf("%d\n",ss);
}
代码不必多说了吧~
8780:拦截导弹
描述
某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统。但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度,但是以后每一发炮弹都不能高于前一发的高度。某天,雷达捕捉到敌国的导弹来袭。由于该系统还在试用阶段,所以只有一套系统,因此有可能不能拦截所有的导弹。
输入导弹依次飞来的高度(雷达给出的高度数据是不大于30000的正整数),计算这套系统最多能拦截多少导弹。
输入 第一行是一个整数N(不超过15),表示导弹数。第二行包含N个整数,为导弹依次飞来的高度(雷达给出的高度数据是不大于30000的正整数)。 输出 一个整数,表示最多能拦截的导弹数。 样例输入
8 389 207 155 300 299 170 158 65样例输出
6
这道题与上道题几乎一模一样,相当于求一组数里的最长不上升子序列,解法相同
代码就不必丢了吧~
4977:怪盗基德的滑翔翼
描述
怪盗基德是一个充满传奇色彩的怪盗,专门以珠宝为目标的超级盗窃犯。而他最为突出的地方,就是他每次都能逃脱中村警部的重重围堵,而这也很大程度上是多亏了他随身携带的便于操作的滑翔翼。
有一天,怪盗基德像往常一样偷走了一颗珍贵的钻石,不料却被柯南小朋友识破了伪装,而他的滑翔翼的动力装置也被柯南踢出的足球破坏了。不得已,怪盗基德只能操作受损的滑翔翼逃脱。
假设城市中一共有N幢建筑排成一条线,每幢建筑的高度各不相同。初始时,怪盗基德可以在任何一幢建筑的顶端。他可以选择一个方向逃跑,但是不能中途改变方向(因为中森警部会在后面追击)。因为滑翔翼动力装置受损,他只能往下滑行(即:只能从较高的建筑滑翔到较低的建筑)。他希望尽可能多地经过不同建筑的顶部,这样可以减缓下降时的冲击力,减少受伤的可能性。请问,他最多可以经过多少幢不同建筑的顶部(包含初始时的建筑)?
每组测试数据包含两行:第一行是一个整数N(N < 100),代表有N幢建筑。第二行包含N个不同的整数,每一个对应一幢建筑的高度h(0 < h < 10000),按照建筑的排列顺序给出。 输出 对于每一组测试数据,输出一行,包含一个整数,代表怪盗基德最多可以经过的建筑数量。 样例输入
3 8 300 207 155 299 298 170 158 65 8 65 158 170 298 299 155 207 300 10 2 1 3 4 5 6 7 8 9 10样例输出
6 6 9
#include<cstdio>
#include<algorithm>
using namespace std;
int a[1001],h1[1001],h2[1001],l,r,n;
int main()
{
int i,j,nn;
scanf("%d",&nn);
while(nn)
{
nn--;
scanf("%d",&n);
l=0;
r=0;
for(i=0;i<n;i++)
scanf("%d",&a[i]);
for(i=0;i<n;i++)
{
h1[i]=1;
for(j=0;j<i;j++)
{
if(a[j]<=a[i])
h1[i]=max(h1[j]+1,h1[i]);
}
l=max(l,h1[i]);
}
for(i=n-1;i>=0;i--)
{
h2[i]=1;
for(j=n-1;j>i;j--)
{
if(a[j]<=a[i])
h2[i]=max(h2[j]+1,h2[i]);
}
r=max(r,h2[i]);
}
printf("%d\n",max(l,r));
}
}
1996:登山
五一到了,PKU-ACM队组织大家去登山观光,队员们发现山上一个有N个景点,并且决定按照顺序来浏览这些景点,即每次所浏览景点的编号都要大于前一个浏览景点的编号。同时队员们还有另一个登山习惯,就是不连续浏览海拔相同的两个景点,并且一旦开始下山,就不再向上走了。队员们希望在满足上面条件的同时,尽可能多的浏览景点,你能帮他们找出最多可能浏览的景点数么?
Line 2: N个整数,每个景点的海拔 输出 最多能浏览的景点数 样例输入
8 186 186 150 200 160 130 197 220样例输出
4
#include<cstdio>
#include<algorithm>
using namespace std;
int a[1001],h1[1001],h2[1001],k,g=-1;
void work(int x)
{
int i,j;
for(i=g;i>=x;i--)
{
h2[i]=1;
for(j=g;j>i;j--)
{
if(a[j]<a[i])
h2[i]=max(h2[j]+1,h2[i]);
}
}
k=max(k,h2[x]+h1[x]-1);
}
int main()
{
int n,h,i,j;
scanf("%d",&n);
for(i=0;i<n;i++)
{
scanf("%d",&h);
if(h!=a[g])
{
g++;
a[g]=h;
}
}
for(i=0;i<=g;i++)
{
h1[i]=1;
for(j=0;j<i;j++)
{
if(a[j]<a[i])
h1[i]=max(h1[j]+1,h1[i]);
}
work(i);
}
printf("%d",k);
}
90:滑雪
1 2 3 4 5 16 17 18 19 6 15 24 25 20 7 14 23 22 21 8 13 12 11 10 9
一个人可以从某个点滑向上下左右相邻四个点之一,当且仅当高度减小。在上面的例子中,一条可滑行的滑坡为24-17-16-1。当然25-24-23-...-3-2-1更长。事实上,这是最长的一条。 输入 输入的第一行表示区域的行数R和列数C(1 <= R,C <= 100)。下面是R行,每行有C个整数,代表高度h,0<=h<=10000。 输出 输出最长区域的长度。 样例输入
5 5 1 2 3 4 5 16 17 18 19 6 15 24 25 20 7 14 23 22 21 8 13 12 11 10 9样例输出
25
#include<cstdio>
#include<cmath>
#include<cstring>
#include<iostream>
using namespace std;
int a[120][120],h[120][120],m,n,longest;
void ill()
{
int i,j;
for(i=0;i<m;i++)
for(j=0;j<n;j++)
{
if(a[i-1][j]>a[i][j]&&i>0)
h[i][j]=max(h[i-1][j]+1,h[i][j]);
if(a[i+1][j]>a[i][j]&&i<m-1)
h[i][j]=max(h[i+1][j]+1,h[i][j]);
if(a[i][j-1]>a[i][j]&&j>0)
h[i][j]=max(h[i][j-1]+1,h[i][j]);
if(a[i][j+1]>a[i][j]&&j<n-1)
h[i][j]=max(h[i][j+1]+1,h[i][j]);
longest=max(longest,h[i][j]);
}
for(i=m-1;i>=0;i--)
for(j=n-1;j>=0;j--)
{
if(a[i-1][j]>a[i][j]&&i>0)
h[i][j]=max(h[i-1][j]+1,h[i][j]);
if(a[i+1][j]>a[i][j]&&i<m-1)
h[i][j]=max(h[i+1][j]+1,h[i][j]);
if(a[i][j-1]>a[i][j]&&j>0)
h[i][j]=max(h[i][j-1]+1,h[i][j]);
if(a[i][j+1]>a[i][j]&&j<n-1)
h[i][j]=max(h[i][j+1]+1,h[i][j]);
longest=max(longest,h[i][j]);
}
}
int main()
{
int i,j;
scanf("%d%d",&m,&n);
for(i=0;i<m;i++)
for(j=0;j<n;j++)
h[i][j]=1;
for(i=0;i<m;i++)
for(j=0;j<n;j++)
scanf("%d",&a[i][j]);
for(i=0;i<100;i++)
ill();
printf("%d",longest);
}
感激不敬!!