2017.2.09【初中部 GDKOI】模拟赛B组 拦截导弹 题解

原题:

http://172.16.0.132/senior/#contest/show/1916/2

题目描述:

在很久以前,A国发明一套导弹拦截系统来防御敌国发射的导弹。这套系统能通过发射一枚导弹来拦截敌人的多枚导弹,但该导弹每次只能按距离由近到远拦截比它当前高度低(或等于当前高度)的导弹。
最近,有学者发现这套系统并不够强大,所以他们发明了另一套导弹拦截系统。同样的该系统也是发射一枚导弹拦截敌人的多枚导弹,并且也是由距离近的导弹向距离远的导弹进行拦截。当拦截导弹发射后,第一次它可选择任一枚导弹进行拦截,然后它可拦截比当前导弹距离远、高度低的导弹,接着它可拦截比当前导弹距离远、高度高的导弹……就是说,该拦截导弹在奇数次将拦截比前一枚导弹距离远、高度高的导弹,在偶数次将拦截比前一枚导弹距离远、高度低的导弹。
现在,有近到远给出了敌国发射过来的导弹的高度,请你计算出一枚该拦截导弹最多能拦截到多少枚导弹。

输入:

输入包含多组数据。对于每组数据,第一行是一个整数N,(1<=N<=1000),表示敌国发射的导弹数。接下来一行由近及远的给出N个整数h(0<=h<=10^9),表示导弹的高度。输入数据以N=0结束。

输出:

对于每组数据,输出一个整数,为一枚拦截导弹最多能拦截的导弹数量。

样例输入:

4
5 3 2 4
3
1 1 1
0

样例输出:

3
1

分析:

由题目给出:该拦截导弹在奇数次将拦截比前一枚导弹距离远、高度高的导弹,在偶数次将拦截比前一枚导弹距离远、高度低的导弹。
本题很易想到搜索,但题目给出敌国的导弹数可能是N<=1000的。
于是考虑使用动态规划:
这个题目从选择一个目标出发,然后有不同的拦截方法,由此我们可以把问题分解为:发射一枚导弹可以栏到那颗敌弹止,能栏到多少敌弹的子问题,由近到远进行求解这些子问题,找到一个最大值。
这个思路满足动态规划的解题条件:状态必须满足最优化原理和无后效性两个条件。
设:
max[i][1]表示当拦到第i枚敌弹时是第奇数次拦截,这时最多能拦到多少敌弹;
max[i][2]表示当拦到第i枚敌弹时是第偶数次拦截,这时最多能拦到多少敌弹;
Ans为最多拦截数量,num为输入的敌方导弹高度;
状态转移方程:
Max[i,2]:=max[j,1]+1;
当:num[j]>num[i],且有max[j,1]>max[i,2],j

实现:

#include<cstdio>
#include<iostream>
using std::max;

int n,i,j,a[1001],f[1001]; 
int main() 
{
    while(true)
    {
        scanf("%d",&n);
        if(n==0) break;
        for(i=1;i<=n;i++) scanf("%d",&a[i]);
        for(i=1;i<=n;i++)
        {
            f[i]=1;
            for(j=1;j<i;j++)
                if(f[j]%2==1&&a[j]>a[i]||f[j]%2==0&&a[j]<a[i]) f[i]=max(f[i],f[j]+1);
        }
        printf("%d\n",f[n]);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值