【题解】「NOIP1999 普及组」导弹拦截(DP,最长不下降子序列+贪心)

题面

【题目描述】
某国为了预防敌国的导弹袭击,发展出一种导弹拦截系统。但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够达到任意的高度,但是以后每一发炮弹都不能高于前一发的高度。某天,雷达捕捉到敌国的导弹来袭。由于该系统还在试用阶段,所以只有一套系统,因此有可能不能拦截所有的导弹。
输入导弹依次飞来的高度(雷达给出的高度数据是不大于 30000 30000 30000的正整数,导弹数不超过 1000 1000 1000),计算这套系统最多能拦截多少导弹,如果要拦截所有导弹最少要配备多少套这种导弹拦截系统。
【输入】
一行,输入导弹依次飞来的高度
【输出】
共两行,第1行为最多拦截的导弹数,第2行输出要拦截所有导弹最少要配备的系统数
【样例输入】

389 207 155 300 299 170 158 65

【样例输出】

6
2

算法分析

本题有两个问题,先看第一问。
问题一:这套系统最多能拦截多少导弹?
假设拦截的导弹高度为 h 1 , h 2 , h 3 . . h k h_1,h_2,h_3..h_k h1,h2,h3..hk,它们需要满足的关系是 h 1   = h 2 > = h 3 > = . . > = h k h_1\>= h_2>= h_3>= .. >= h_k h1=h2>=h3>=..>=hk,这就是最长不上升子序列。

问题二:要拦截所有导弹最少要配备多少套这种导弹拦截系统
假设目前有 m m m套拦截系统,能够拦截的导弹最高高度为 h 1 , h 2 , h 3 . . h k h_1,h_2,h_3..h_k h1,h2,h3..hk,现在有一枚导弹高度为 H H H,如果 m m m套系统都能拦截,那么选择哪一套系统呢?
选择能够拦截 H H H且拦截高度最小的拦截系统去拦截,把拦截高度高的留着拦截更高的导弹,这就是贪心的方法。
因此,可以使用数组 s s s表示每套拦截系统的高度。如果所有拦截系统都不能拦截,拦截系统就增加一套。

参考程序

#include<iostream>
using namespace std;
int a[1100],f[1100],s[1100];
int main()
{
    int ans=0,n=1;
    while(cin>>a[n])	//输入 
    {
        n++;
    }
    for(int i=1;i<n;i++)	//最长不上升子序列 
    {
        int falg=1,t=0;
        for(int j=i-1;j>=1;j--)
        {
            if(a[j]>=a[i])
            {
                if(f[j]>t) 
                    t=f[j];
                falg=0;
            }
        }
        if(falg) f[i]=1;
        else f[i]=t+1;
        ans=max(ans,f[i]);
    }
    cout<<ans<<endl;
    int m=0,p;
    for(int i=1;i<=n;i++)
    {
        int x=9999999,flag=1;
        for(int k=1;k<=m;k++)
        {
            if(s[k]>=a[i])
            {
                if(s[k]<=x) {x=s[k];p=k;}		//选择能够拦截,且高度最小的拦截系统
                flag=0;
            }
        }
        if(flag) {m++;s[m]=a[i];}		//不能拦截就增加一套系统m++,新系统拦截高度=a[i]
        else s[p]=a[i];					
    } 
    cout<<m<<endl;
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值