题目
某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统.但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度,但是以后每一发炮弹都不能超过前一发的高度.某天,雷达捕捉到敌国的导弹来袭.由于该系统还在试用阶段,所以只有一套系统,因此有可能不能拦截所有的导弹.
怎么办呢?多搞几套系统呗!你说说倒蛮容易,成本呢?成本是个大问题啊.所以俺就到这里来求救了,请帮助计算一下最少需要多少套拦截系统.
传送门
题意分析
第一次看的时候还以为是直接求断点个数,后来发现不是这么简单。直接求断点的话就会忽略掉后面的导弹可以用更前面的系统解决的情况。在看了网上一些题解都提到了最长递增子序列和求解,即最长递增子序列中的元素个数就是需要的系统数。原因大概就是因为如果遇到最长递增子序列的元素后,就必须用一个新系统才能解决这个导弹,而前面所有的系统都不能解决。但是由于想起来会有点抽象,我这里采用的是另一种更形象的方法,还是用dp。定义
dp[i]为已经使用的第i个系统打的最后一颗导弹的最后高度,也可以理解为第i个系统能打到的高度。那么第 i 颗导弹实际上就有2种去处, 第一种是如果a【i】>dp【1~i-1】,那么a[i]就不能加入前面任何一个系统中,那么需要的系统数+1,并且dp[i] = a[i],因为第i个系统的最后一个高度就是a[i];第二种情况是a[i]<dp[1~i]中的某一个数,如果存在多种情况,那么就i加入dpk最小的,因为不管加入哪个系统中,都将导致系统能打到的高度为a[i],那么不如就留dp[k]比较大的下来,有点贪心的意思,相当于将第i颗导弹用满足条件的且能打到高度最低的系统解决。记录下哪个系统的下标,即第几个系统,系统个数还是不变,然后更新该系统的值为a[i] 那么核心代码为:
18 int ans = 1;
19 dp[ans] = a[1];
20 for (int i = 1; i <= n; i++){
21 int idex;
22 int stemp = INF; //判断是不是有符合条件的系统
23 for (int j = 1 ;j <= ans; j ++){
24 if (a[i] <= dp[j]){
25 if (stemp >= dp[j]){
26 stemp = dp[j]; //不断找出最小的
27 idex = j;
28 }
29