AcWing1010_拦截导弹

题目链接:AcWing1010.拦截导弹

1. 题目描述

某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统。

但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度,但是以后每一发炮弹都不能高于前一发的高度。

某天,雷达捕捉到敌国的导弹来袭。

由于该系统还在试用阶段,所以只有一套系统,因此有可能不能拦截所有的导弹。

输入导弹依次飞来的高度(雷达给出的高度数据是不大于 30000 30000 30000 的正整数,导弹数不超过 1000 1000 1000 ),计算这套系统最多能拦截多少导弹,如果要拦截所有导弹最少要配备多少套这种导弹拦截系统。

输入格式
共一行,输入导弹依次飞来的高度。

输出格式
第一行包含一个整数,表示最多能拦截的导弹数。

第二行包含一个整数,表示要拦截所有导弹最少要配备的系统数。

数据范围
雷达给出的高度数据是不大于 30000 30000 30000 的正整数,导弹数不超过 1000 1000 1000

输入样例:

389 207 155 300 299 170 158 65

输出样例:

6
2

2. 题目分析

  • 条件1:第一发炮弹能够到达任意的高度,但是以后每一发炮弹都不能高于前一发的高度。
  • 目标:这套系统最多能拦截多少导弹,如果要拦截所有导弹最少要配备多少套这种导弹拦截系统。

由条件1可知,“第一发炮弹可以选任意高度,后面的炮弹不能高于前一发的高度:”,说明我们要找一个下降子序列。
由目标可知,第一问是要找一个最长下降子序列,直接求反向的最长上升子序列即可,具体解法可见AcWing895_最长上升子序列

对于第二问,有如下分析:

  1. 首先对于每一个数,我们可以将其接在一个现有的子序列之后,也可以创建一个新的子序列。
  2. 当我们将其接到一个子序列后面时,一定是所有满足要求子序列的最小的那一个(就是最后一个数是满足要求的最小的那一个)。

所以我们可以通过贪心法解决第二问。

贪心流程:
从前往后扫描每一个数,对于每个数:

  1. 如果现有子序列的结尾都小于当前数,则创建新的子序列。
  2. 将当前数放到结尾大于等于他的最小的子序列后面。

3. 代码实现

#include <iostream>
#include <algorithm>

using namespace std;

const int N = 1010;

int n, cnt;
int a[N];
int f[N], g[N];

int main()
{
    while (~scanf("%d", &a[n])) n ++;
    
    int res = 0;
    for (int i = n - 1; i >= 0; i -- )
    {
        f[i] = 1;
        for (int j = n - 1; j > i; j -- )
            if (a[j] <= a[i])
                f[i] = max(f[i], f[j] + 1);
        res = max(res, f[i]);      
    }
    
    printf("%d\n", res);
    
    for (int i = 0; i < n; i ++ )
    {
        int k = 0;
        while (k < cnt && g[k] < a[i]) k ++;
        g[k] = a[i];
        if (k >= cnt) cnt ++;
    }
    
    printf("%d\n", cnt);
    return 0;
}

4. 时间复杂度

O ( n 2 ) O(n^2) O(n2)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
根据引用\[1\]和引用\[2\]的代码,这是一个动态规划问题。问题描述为阿福想要在不惊动警察的情况下,洗劫一条街上的店铺,每家店铺中都有一些现金。阿福只能同时洗劫两家相邻的店铺,否则会触发报警系统。阿福想知道,在这种情况下,他今晚最多可以得到多少现金。 根据引用\[2\]的代码,动态规划的思路是定义一个数组f,其中f\[i\]表示只偷窃前i个店铺的情况下所能得到的最大现金。初始条件为f\[0\]=0和f\[1\]=a\[1\],其中a\[1\]是第一个店铺的现金。然后根据状态转移方程f\[i\] = max{f\[i-1\], a\[i\] + f\[i-2\]},计算出f\[n\],即为阿福今晚最多可以得到的现金。 根据引用\[1\]的代码,可以看到在每次循环中,dp\[i\]\[0\]表示不偷窃第i家店铺的最大现金,dp\[i\]\[1\]表示偷窃第i家店铺的最大现金。根据状态转移方程dp\[i\]\[0\] = max{dp\[i-1\]\[0\], dp\[i-1\]\[1\]}和dp\[i\]\[1\] = dp\[i-1\]\[0\] + a\[i\],计算出dp\[n\]\[0\]和dp\[n\]\[1\],然后取其中较大的值作为阿福今晚最多可以得到的现金。 综上所述,根据引用\[2\]的代码,阿福今晚最多可以得到的现金为f\[n\],根据引用\[1\]的代码,阿福今晚最多可以得到的现金为max(dp\[n\]\[0\], dp\[n\]\[1\])。 #### 引用[.reference_title] - *1* [AcWing 1049. 大盗阿福](https://blog.csdn.net/qq_43254375/article/details/104605407)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* *3* [【ACWing】1049. 大盗阿福](https://blog.csdn.net/qq_46105170/article/details/114259818)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值