拦截导弹

问题描述:

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

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

样例:

 Input: 389 207  155  300  299  170  158  65

Output: 6(最多拦截导弹数)

        2(要拦截所有导弹最少要配备的系统数)

运行示例:

INPUT: 300 250 275 252 200 138 245

OUTPUT: 5 2

INPUT: 181 205 471 782 1033 1058 1111

OUTPUT: 1 7

INPUT: 465 978 486 324 575 384 278 214 657 218 445 123

OUTPUT: 6 4

INPUT: 236 865 858 565 545 445 455 656 844 735 638 652 569 714 845

OUTPUT: 6 7

 

问题分析

  第一问可以抽象为,求一组数列的最长降序列。设st(n)为数组中以第n个数为头的最长递减序列长度。st(n-1)=max(st(x1),st(x2)...st(xi))+1. 其中n<=xi<=N,并且数组中第xi个数要小于第n-1个数。可以用递归。

  第二问:用链表存储n个高度。先找链表中最大的数,并纪录最大数的下一个位置t,删除那个最大的数。再从t开始找最大的数,再纪录再删除。直到t为表尾,结束一轮。系统数加1。再从表头开始重复上一步,直到链表为空。
例如:7 6 2 8 5 3
先找到8,删除8。再从5开始找,5最大删除。再从3开始,3为表尾删除,并结束一轮。
再从表头7开始找,删除762后表为空。停止 系统即:8 5 37 6 2

第二问的算法可以用一个有向无环图来证明。


数据结构

  第一问用数组存储n个高度。程序中用high[]这个数组。

  第二问用带头结点的单链表来储存n个数字。

typedef struct Node

{

    int val;

    struct Node *next;

}Node,*Link;

 

程序清单

#include <stdio.h>

#define N 100

int high[N+1]={0};

int k=0;

int system=0;

 

int NoMaxSq(int n)

{

    int i,max;

    if(n==k)

        return 1;

    else

    {

        max=0;

        for(i=n+1;i<=k;i++)

        {

            if(high[i]<high[n])

                max=NoMaxSq(i);

            break;

        }

        for(i=n+1;i<=k;i++)

        {

            if(high[i]<high[n])

                if(NoMaxSq(i)>max)

                    max=NoMaxSq(i);

        }

 

        return max+1;

 


    }

}

 

 

 

typedef struct Node

{

    int val;

    struct Node *next;

}Node,*Link;

 

Node *PriorElem(Link L,Node *t)

{ 

    Node *p=L;

    while((p!=0)&&(p->next!=t))

        p=p->next;

    return p;

}

 

 

void SystemNo()

{

    int i,max;

    Node *p,*t,*q;

    Node *mp,*temp;

    Link L;

    L=(Link) malloc(sizeof(Node));

    L->next=NULL;

    for(i=k;i>0;--i)

    {

        p=(Link)malloc(sizeof(Node));

        p->val=high[i];

        p->next=L->next;L->next=p;

    }

    do

    {

        t=L->next;

        do

        {

            q=PriorElem(L,t);

            for(max=t->val;t;q=t,t=t->next)

                if(max<=t->val)

                {

                   max=t->val;

                   temp=t;

                   mp=q; 

                }

            mp->next=temp->next;

            free(temp);

             t=mp->next;

        }while(t);

        ++system;

    }while(L->next);

 

 

}

 

 

main()

{

    void SystemNo();

 

    int i=0,n=0;

    int max;

    char c;

    char s[100];

    while((c=getchar())!='/n')

    {

        s[i++]=c;

    }

    s[i]='/0';

    i=0;

    while(s[i]!='/0')

    {

        if(s[i]==' ')

            i++;

        for(;s[i]>='0'&&s[i]<='9';++i)

            n=10*n+(s[i]-'0');

        high[++k]=n;

 

        n=0;

    }

    max=0;

 

    for(i=1;i<=k;i++)

        if(max<NoMaxSq(i))

            max=NoMaxSq(i);

    printf("%d",max);

    SystemNo();

    printf("      %d",system);

    getch();

}

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值