题目描述:
某国为了防御敌国的导弹袭击,发明出一种导弹拦截系统。但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度,但是以后每一发炮弹都不能高于前一发的高度。
某天,雷达捕捉到敌国的导弹来袭。由于该系统还在试用阶段,所以只有一套系统,因此有可能不能拦截所有的导弹。
现在,要你计算出这套系统最多能拦截多少枚导弹,并且如果要拦截所有导弹的话,最少要配备多少套这种导弹拦截系统。
输入格式:
输入数据为两行。
第一行为一个整数,表示导弹的数目N。
第二行为N个整数,表示第i枚导弹飞来的高度Hi。
输出格式:
输出只有一行。
这一行只有两个整数,即这套系统最多能拦截的导弹数和要拦截所有导弹最少要配备这种导弹拦截系统的套数。
数据范围:
1≤N≤1000,1≤Hi≤30000。
样例输入:
8
389 207 155 300 299 170 158 65
样例输出:
6 2
问题分析:
这是一道很典型的动态规划求最长不上升子序列和最长上升子序列的题,我们用a数组记录导弹依次飞来的高度,用opt1数组记录之前能拦截的某一导弹的已拦截数,用opt2数组记录之前能一次性拦截的系统的套数。所以很容易地就能写出动态转移方程:
opt1[i]=opt1[j]+1(0<j<i且a[j]≥a[i]且opt1[j]+1>opt1[i])
opt2[i]=opt2[j]+1(0<j<i且a[j]<a[i]且opt2[j]+1>opt2[i])
参考程序:
1 #include<stdio.h>
2 int a[10000],opt1[10000],opt2[10000];
3 int n,anslen,anstime;
4 int main()
5 {
6 int i,j;
7 scanf("%d",&n);/*输入导弹的数目*/
8 for(i=1;i<=n;i++)
9 scanf("%d",&a[i]);/*输入各个导弹依次飞来的高度*/
10 opt1[1]=1;
11 for(i=2;i<=n;i++)
12 {
13 opt1[i]=1;
14 for(j=i-1;j>0;j--)
15 if(a[j]>=a[i]&&opt1[j]+1>opt1[i]) opt1[i]=opt1[j]+1;/*如果这枚导弹的高度小于等于以前的导弹的高度并且以前导弹的已拦截数大于等于这枚导弹的已拦截数的话,那就把这枚导弹的已拦截数在原来导弹的已拦截数的基础上再加1*/
16 }
17 anslen=0;
18 for(i=1;i<=n;i++)
19 if(opt1[i]>anslen) anslen=opt1[i];
20 opt2[1]=1;
21 for(i=2;i<=n;i++)
22 {
23 opt2[i]=1;
24 for(j=i-1;j>0;j--)
25 if(a[j]<a[i]&&opt2[j]+1>opt2[i]) opt2[i]=opt2[j]+1;26 }
27 anstime=0;
28 for(i=1;i<=n;i++)
29 if(opt2[i]>anstime) anstime=opt2[i];
30 printf("%d %d",anslen,anstime);
31 return 0;
32 }
浙公网安备 33010602011771号