最少拦截系统
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 34091 Accepted Submission(s): 13390
Problem Description
某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统.但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度,但是以后每一发炮弹都不能超过前一发的高度.某天,雷达捕捉到敌国的导弹来袭.由于该系统还在试用阶段,所以只有一套系统,因此有可能不能拦截所有的导弹.
怎么办呢?多搞几套系统呗!你说说倒蛮容易,成本呢?成本是个大问题啊.所以俺就到这里来求救了,请帮助计算一下最少需要多少套拦截系统.
Input
输入若干组数据.每组数据包括:导弹总个数(正整数),导弹依此飞来的高度(雷达给出的高度数据是不大于30000的正整数,用空格分隔)
Output
对应每组数据输出拦截所有导弹最少要配备多少套这种导弹拦截系统.
Sample Input
8 389 207 155 300 299 170 158 65
Sample Output
2
这题以前写过。。训练的时候出在dp的模块,但是仔细想,我用的是贪心。炮弹飞来的高度和时间都是确定的,每个炮弹都要被拦截,那么在有炮弹飞来的情况下,我们开一套拦截系统来打,当出现打不到的高度时,我们开第二套系统。
那么这里有一个问题,当炮弹飞来时,我们要用已经开了的哪一套系统来打飞来的炮弹呢?假设已经有两套系统,一套现在只能打到150的高度,另一套能打到100的高度,现在来了一个高度为10的炮弹,要用哪一套呢?答案是,用100的打。要明确100是怎么来的,出现150这套系统是因为100的那套系统在某次拦截时已经打不到150的高度了,这里的贪心存在一种递推关系,第一套系统总是最先打到最低的炮弹。
补充:今天在知乎上看到了这一条回复,个人觉得挺有道理的,大家可以看一下:
答主的id:大雄
贪心是一种特殊的动态规划,动态规划的本质是独立的子问题,而贪心则是每次可以找到最优的独立子问题。
贪心和动归不是互斥的,而是包含的,贪心更快,但约束更强,适应范围更小。
动归和bfs的关系也是一样的。
展开一点讲,在求解最优化问题时,有多个解。而求解的过程类似一个树,我们称之为求解树。
一般的求解树真的是一棵树,所以我们只能用bfs来搜索,顶多剪枝。
有些特殊的求解树,中间很多结点是重合的,结点个数比所有解的个数少很多个数量级。这类问题较特殊,我们可以保存中间的搜索过程。而记忆化搜索和动态规划本质上就是一个东西,快就快在可以不用重复计算很多中间结果(所谓的最优子问题)。
还有一些特殊的求解树,更特殊,它们不止有很多重复结点,而且每次选择分支的时候,我们可以证明只要选择一个分支,这个分支的解就一定比其他选择更优。这类问题就是贪心了,
所以bfs,dp,贪心三个方法都是解决最优化问题的方法,根据问题的不同,约束越大的问题可以用越快的方法,越慢的方法可以解决的问题越普适。
代码:
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;
const int maxn = 10000+10;
int height[maxn];
int dp[maxn];
int main(){
int n;
while(cin>>n){
for(int i=0; i<n; i++)
cin>>height[i];
int cnt = 0;
for(int i=0; i<n; i++){
if(i==0)
dp[cnt] = height[i];
else{
bool flag = false;
for(int j=0; j<=cnt; j++){
if(height[i]<=dp[j]){
dp[j] = height[i];
flag = true;
break;
}
}
if(!flag){
cnt++;
dp[cnt] = height[i];
}
}
}
cout<<cnt+1<<endl;
}
return 0;
}