在一个已知的序列{ a1,a2,……am}中,取出若干数组成新的序列{ ai1, ai2,…… aim},其中下标 i1,i2, ……im保持递增,即新数列中的各个数之间依旧保持原数列中的先后顺序,那么称{ ai1, ai2,……aim}为原序列的一个子序列。若在子序列中,当下标 ix > iy时,aix > aiy,那么称其为原序列的一个递增子序列。最长递增子序列问题就是在一个给定的原序列中,求得其最长递增子序列的长度。
求最长递增子序列的递推公式为:
F(1) = 1;
F(i) = max{ 1, F[j]+1 | aj<ai && j<i}
拦截导弹
题目描述
某国为了防御敌国的导弹袭击,开发出一种导弹拦截系统。但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度,但是以后每一发炮弹都不能高于前一发的高度。某天,雷达捕捉到敌国的导弹来袭,并观测到导弹依次飞来的高度,请计算这套系统最多能拦截多少导弹。拦截来袭导弹时,必须按来袭导弹袭击的时间顺序,不允许先拦截后面的导弹,再拦截前面的导弹。
输入描述:
每组输入有两行, 第一行,输入雷达捕捉到的敌国导弹的数量k(k<=25), 第二行,输入k个正整数,表示k枚导弹的高度,按来袭导弹的袭击时间顺序给出,以空格分隔。
输出描述:
每组输出只有一行,包含一个整数,表示最多能拦截多少枚导弹。
示例1
输入
8 300 207 155 300 299 170 158 65
输出
6
解题思路:要求最多能拦截多少枚导弹,即在按照袭击顺序排列的导弹高度中求其最长不增子序列。其中
F(1) = 1;
F(i) = max{ 1, F[j]+1 | aj>=ai && j<i}
1 #include<stdio.h> 2 #include<stdlib.h> 3 4 int list[26]; //按顺序保存导弹高度 5 int dp[26]; //保存以第i个导弹结尾的最长不增长序列长度 6 int max( int a,int b) 7 { 8 //选取最大值 9 return a>b? a:b; 10 } 11 int main() 12 { 13 int n; 14 int tmax,ans; 15 int i,j; 16 while( scanf("%d",&n)!=EOF) 17 { 18 for( i=1; i<=n; i++) 19 { 20 scanf("%d",&list[i]); 21 dp[i] = 0; 22 } 23 for( i=1; i<=n; i++) 24 { 25 tmax = 1; //最长不增长子序列长度至少为1 26 for( j=1; j<i; j++) //遍历其前所有导弹高度 27 { 28 if( list[j]>=list[i]) //若j号导弹不比当前导弹低 29 { 30 tmax = max( tmax,dp[j]+1); 31 } 32 } 33 dp[i] = tmax; 34 } 35 ans = 1; 36 for( i=1; i<=n; i++) 37 ans = max( ans, dp[i]); 38 printf("%d\n",ans); 39 } 40 41 return 0; 42 }