dp求解导弹拦截问题

本文介绍如何使用动态规划解决导弹拦截系统的问题,通过找到最长递减序列的元素个数,确定一套系统能拦截的导弹数量。提供递归和非递归两种算法实现,以应对不同导弹高度数据,最终给出拦截所有导弹所需的系统套数。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Problem
某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统。但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够达到任意的高度,但是以后每一发炮弹都不能高于前一发的高度。某天,雷达捕捉到敌国的导弹来袭。由于该系统还在使用阶段,所以只有一套系统,因此有可能不能拦截所有的导弹。 

Input
最多20个整数,分别表示导弹依次飞来的高度(雷达给出高度数据是不大于30000的正整数) 

Output
两个整数M和N。表示:这套系统最多能拦截 M 枚导弹,如果要拦截所有导弹最少要配备 N 套这种导弹系统。 

Sample Input
300 250 275 252 200 138 245

Sample Output
5 2

递推公式如下:



/*
    功能:求最长递减序列的元素个数以及最长非递减序列的元素个数
    开发环境:Codeblocks 16.01
    作者:发烧的小龙虾
    日期:2017.9.25
    解题思路:这题有两问,第一问要我们求输入序列的最长递减序列的元素个数。
可以用动态规划的思想来求解,本人用了两种方法进行求解,一个是递归算法,一个
是非递归算法,但是两种算法的思想都是基于一个递归函数来实现的。设一个数组dp[]
,其中dp[i]表示的是以dp[i]为递减序列的最后一个元素时这个递减序列的元素个数。
当i=0时,显然dp[i]=dp[0]=1;当i不等于0时,就应该找出从编号为k(k=0,1,...i-1)的
元素中找出所有满足h[k]<h[i]的元素集合,并找出这些元素集合中dp值最大的那一个作
dp[i]的值。对于第二问,只需要找出最长非递减序列的个数就行了,因为最长非递减序列
中任意两个元素都不可能被同一个系统射中(因为不满足递减规律),因此至少得有这么
套系统!
    备注:由于思路是一样的,所以求最长非递减序列的元素个数的算法只给出非递归的
形式!
*/
#include <iostream>
#include<cstring>
using namespace std;
int digui(int h[],int i) /*递归法求解,函数返回的是dp[i]的值*/
{
    if(i==0)  /*如果就是第一个,说明它就单独是一类,因为它前面没有元素了*/
        return 1; /*返回1*/
    int max=0;  /*初始化max*/
    for(int k=0;k<i;k++) /*从前面的所有元素中开始寻找*/
      if(h[k]>h[i]&&max<digui(h,k))
        max=digui(h,k);
    return max+1;
}
void feidigui(int h[],int dp[],int n)
{
    int max;
    dp[0]=1;
    for(int i=1;i<n;i++){
        max=0;
        for(int j=0;j<i;j++)
            if(h[j]>h[i]&&max<dp[j])
               max=dp[j];
        dp[i]=max+1;
    }
}
int digui_z(int h[],int i)
{
    if(i==0)
        return 1;
    int max=0;
    for(int k=0;k<i;k++)
      if(h[k]<h[i]&&max<digui_z(h,k))
        max=digui_z(h,k);
    return max+1;
}
int main()
{
    int max,h[20],dp[20],n;
    max=0;
    memset(dp,0,sizeof(dp));
    cout<<"请输入导弹的个数,这个数不要超过20!"<<endl;
    cin>>n;
    cout<<"请输入"<<n<<"个导弹的高度"<<endl;
    for(int i=0;i<n;i++)
        cin>>h[i];
    feidigui(h,dp,n);
    for(int i=0;i<n;i++)
        if(max<dp[i])
            max=dp[i];
    cout<<"用非递归的方法求出的最多可以拦截的导弹数是"<<max<<"!"<<endl;
    max=0;
    for(int i=0;i<n;i++)
        if(max<digui(h,i))
            max=digui(h,i);
    cout<<"用递归的方法求出的最多可以拦截的导弹数也是"<<max<<"!"<<endl;
    max=0;
    for(int i=0;i<n;i++)
        if(max<digui_z(h,i))
            max=digui_z(h,i);
    cout<<"用递归的方法求出的至少需要的系统套数为"<<max<<"!"<<endl;
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值