【杭电】[1257]最少拦截系统
|
最少拦截系统Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)
Problem Description
某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统.但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度,但是以后每一发炮弹都不能超过前一发的高度.某天,雷达捕捉到敌国的导弹来袭.由于该系统还在试用阶段,所以只有一套系统,因此有可能不能拦截所有的导弹.
怎么办呢?多搞几套系统呗!你说说倒蛮容易,成本呢?成本是个大问题啊.所以俺就到这里来求救了,请帮助计算一下最少需要多少套拦截系统.
Input
输入若干组数据.每组数据包括:导弹总个数(正整数),导弹依此飞来的高度(雷达给出的高度数据是不大于30000的正整数,用空格分隔)
Output
对应每组数据输出拦截所有导弹最少要配备多少套这种导弹拦截系统.
Sample Input
8 389 207 155 300 299 170 158 65
Sample Output
2
|
考虑若使炮弹命中最多,则炮弹命中导弹的导弹递减
所以需要发射LIS次,以为代表无法调整使其命中更多
n2一般dp算法:
对于每一个a[i]判断a[0~i]能否把它更新成dp[j]+1
也就是看a[i]能否加在a[0~i]中的某个数之后
达到一个新的最大值
#include<stdio.h>
int a[30200],dp[30200];
int main() {
int n;
while(scanf("%d",&n)!=EOF) {
for(int i=0; i<n; i++) {
dp[i]=1;
scanf("%d",&a[i]);
}
int res=0;
for(int i=1; i<n; i++)
for(int j=0; j<i; j++)
if(a[i]>a[j]&&dp[i]<dp[j]+1) {
dp[i]=dp[j]+1;
if(res<dp[i])
res=dp[i];
}
printf("%d\n",res);
}
return 0;
}
nlogn二分算法:
建一个数组保存取的数列的可能性
然后每判断到一个a[i]在s中找到一个s[k]<a[i]<s[k+1]的位置
然后用a[i]替换掉s[k+1]
也就是尽量用小的把使子序列相同的长度替换掉
这样可以保证后面的数比前面的数大的可能性提升
如果查找到s最后还没有a[i]<s[k+1]
则说明a[i]比目前s[k]的每一个数都大
这时候显然要把a[i]加到s的最后面
因为s中的数必然是单调递增的
所以在寻找位置的时候可以进行二分搜索优化时间
二分搜索的实现可以自己写函数
也可以调用C++中的lower_bound
自建函数:
#include <stdio.h>
int inf=99999999;
int n,l;
int a[30200];
int s[30200];
int find(int m) {
int la=0,lb=l;
while(lb>=la) {
int mid=(la+lb)>>1;
if(s[mid]==m)
return mid;
else if(s[mid]>m)
lb=mid-1;
else
la=mid+1;
}
return la;
}
int main() {
while(scanf("%d",&n)!=EOF) {
for(int i=1; i<=n; i++)
scanf("%d",&a[i]);
s[0]=-1;
l=1;
for(int i=1; i<=n; i++) {
s[l]=inf;
int t=find(a[i]);
if(t==l)
l++;
s[t]=a[i];
}
printf("%d\n",l-1);
}
return 0;
}
运用C++函数:
#include <stdio.h>
#include <algorithm>
using namespace std;
int inf=99999999;
int a[30200],s[30200];
int main() {
int n;
while(scanf("%d", &n)!=EOF) {
for(int i=1; i<=n; i++)
scanf("%d",&a[i]),s[i]=inf;
int l=1;
for(int i=1; i<=n; i++) {
int k=lower_bound(s+1,s+n+1,a[i])-s;
if(k==l)
l++;
s[k]=a[i];
}
printf("%d\n",l-1);
}
return 0;
}
题目地址:【杭电】[1257]最少拦截系统